QuotaVFS.cpp (19474B)
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 "QuotaVFS.h" 8 9 #include "mozilla/dom/quota/PersistenceType.h" 10 #include "mozilla/dom/quota/QuotaManager.h" 11 #include "mozilla/dom/quota/QuotaObject.h" 12 #include "mozilla/dom/quota/ResultExtensions.h" 13 #include "mozilla/StaticPrefs_storage.h" 14 #include "nsDirectoryServiceDefs.h" 15 #include "nsEscape.h" 16 #include "sqlite3.h" 17 18 #if defined(XP_WIN) || defined(XP_UNIX) 19 # include "mozilla/StaticPrefs_dom.h" 20 #endif 21 22 // The last VFS version for which this file has been updated. 23 #define LAST_KNOWN_VFS_VERSION 3 24 25 // The last io_methods version for which this file has been updated. 26 #define LAST_KNOWN_IOMETHODS_VERSION 3 27 28 namespace { 29 30 using namespace mozilla; 31 using namespace mozilla::dom::quota; 32 33 struct QuotaFile { 34 // Base class. Must be first 35 sqlite3_file base; 36 37 // quota object for this file 38 RefPtr<QuotaObject> quotaObject; 39 40 // The chunk size for this file. See the documentation for 41 // sqlite3_file_control() and FCNTL_CHUNK_SIZE. 42 int fileChunkSize; 43 44 // This contains the vfs that actually does work 45 sqlite3_file pReal[1]; 46 }; 47 48 already_AddRefed<QuotaObject> GetQuotaObjectFromName(const char* zName) { 49 MOZ_ASSERT(zName); 50 51 const char* directoryLockIdParam = 52 sqlite3_uri_parameter(zName, "directoryLockId"); 53 if (!directoryLockIdParam) { 54 return nullptr; 55 } 56 57 nsresult rv; 58 const int64_t directoryLockId = 59 nsDependentCString(directoryLockIdParam).ToInteger64(&rv); 60 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); 61 62 QuotaManager* quotaManager = QuotaManager::Get(); 63 MOZ_ASSERT(quotaManager); 64 65 return quotaManager->GetQuotaObject(directoryLockId, 66 NS_ConvertUTF8toUTF16(zName)); 67 } 68 69 void MaybeEstablishQuotaControl(const char* zName, QuotaFile* pFile, 70 int flags) { 71 MOZ_ASSERT(pFile); 72 MOZ_ASSERT(!pFile->quotaObject); 73 74 if (!(flags & (SQLITE_OPEN_URI | SQLITE_OPEN_WAL))) { 75 return; 76 } 77 pFile->quotaObject = GetQuotaObjectFromName(zName); 78 } 79 80 /* 81 ** Close a QuotaFile. 82 */ 83 int QuotaClose(sqlite3_file* pFile) { 84 QuotaFile* p = (QuotaFile*)pFile; 85 int rc; 86 rc = p->pReal->pMethods->xClose(p->pReal); 87 if (rc == SQLITE_OK) { 88 delete p->base.pMethods; 89 p->base.pMethods = nullptr; 90 p->quotaObject = nullptr; 91 #ifdef DEBUG 92 p->fileChunkSize = 0; 93 #endif 94 } 95 return rc; 96 } 97 98 /* 99 ** Read data from a QuotaFile. 100 */ 101 int QuotaRead(sqlite3_file* pFile, void* zBuf, int iAmt, sqlite_int64 iOfst) { 102 QuotaFile* p = (QuotaFile*)pFile; 103 int rc; 104 rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst); 105 return rc; 106 } 107 108 /* 109 ** Return the current file-size of a QuotaFile. 110 */ 111 int QuotaFileSize(sqlite3_file* pFile, sqlite_int64* pSize) { 112 QuotaFile* p = (QuotaFile*)pFile; 113 int rc; 114 rc = p->pReal->pMethods->xFileSize(p->pReal, pSize); 115 return rc; 116 } 117 118 /* 119 ** Write data to a QuotaFile. 120 */ 121 int QuotaWrite(sqlite3_file* pFile, const void* zBuf, int iAmt, 122 sqlite_int64 iOfst) { 123 QuotaFile* p = (QuotaFile*)pFile; 124 int rc; 125 if (p->quotaObject) { 126 MOZ_ASSERT(INT64_MAX - iOfst >= iAmt); 127 if (!p->quotaObject->MaybeUpdateSize(iOfst + iAmt, /* aTruncate */ false)) { 128 return SQLITE_FULL; 129 } 130 } 131 rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst); 132 if (p->quotaObject && rc != SQLITE_OK) { 133 NS_WARNING( 134 "xWrite failed on a quota-controlled file, attempting to " 135 "update its current size..."); 136 sqlite_int64 currentSize; 137 if (QuotaFileSize(pFile, ¤tSize) == SQLITE_OK) { 138 DebugOnly<bool> res = 139 p->quotaObject->MaybeUpdateSize(currentSize, /* aTruncate */ true); 140 MOZ_ASSERT(res); 141 } 142 } 143 return rc; 144 } 145 146 /* 147 ** Truncate a QuotaFile. 148 */ 149 int QuotaTruncate(sqlite3_file* pFile, sqlite_int64 size) { 150 QuotaFile* p = (QuotaFile*)pFile; 151 int rc; 152 if (p->quotaObject) { 153 if (p->fileChunkSize > 0) { 154 // Round up to the smallest multiple of the chunk size that will hold all 155 // the data. 156 size = 157 ((size + p->fileChunkSize - 1) / p->fileChunkSize) * p->fileChunkSize; 158 } 159 if (!p->quotaObject->MaybeUpdateSize(size, /* aTruncate */ true)) { 160 return SQLITE_FULL; 161 } 162 } 163 rc = p->pReal->pMethods->xTruncate(p->pReal, size); 164 if (p->quotaObject) { 165 if (rc == SQLITE_OK) { 166 #ifdef DEBUG 167 // Make sure xTruncate set the size exactly as we calculated above. 168 sqlite_int64 newSize; 169 MOZ_ASSERT(QuotaFileSize(pFile, &newSize) == SQLITE_OK); 170 MOZ_ASSERT(newSize == size); 171 #endif 172 } else { 173 NS_WARNING( 174 "xTruncate failed on a quota-controlled file, attempting to " 175 "update its current size..."); 176 if (QuotaFileSize(pFile, &size) == SQLITE_OK) { 177 DebugOnly<bool> res = 178 p->quotaObject->MaybeUpdateSize(size, /* aTruncate */ true); 179 MOZ_ASSERT(res); 180 } 181 } 182 } 183 return rc; 184 } 185 186 /* 187 ** Sync a QuotaFile. 188 */ 189 int QuotaSync(sqlite3_file* pFile, int flags) { 190 QuotaFile* p = (QuotaFile*)pFile; 191 return p->pReal->pMethods->xSync(p->pReal, flags); 192 } 193 194 /* 195 ** Lock a QuotaFile. 196 */ 197 int QuotaLock(sqlite3_file* pFile, int eLock) { 198 QuotaFile* p = (QuotaFile*)pFile; 199 int rc; 200 rc = p->pReal->pMethods->xLock(p->pReal, eLock); 201 return rc; 202 } 203 204 /* 205 ** Unlock a QuotaFile. 206 */ 207 int QuotaUnlock(sqlite3_file* pFile, int eLock) { 208 QuotaFile* p = (QuotaFile*)pFile; 209 int rc; 210 rc = p->pReal->pMethods->xUnlock(p->pReal, eLock); 211 return rc; 212 } 213 214 /* 215 ** Check if another file-handle holds a RESERVED lock on a QuotaFile. 216 */ 217 int QuotaCheckReservedLock(sqlite3_file* pFile, int* pResOut) { 218 QuotaFile* p = (QuotaFile*)pFile; 219 int rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut); 220 return rc; 221 } 222 223 /* 224 ** File control method. For custom operations on a QuotaFile. 225 */ 226 int QuotaFileControl(sqlite3_file* pFile, int op, void* pArg) { 227 QuotaFile* p = (QuotaFile*)pFile; 228 int rc; 229 // Hook SQLITE_FCNTL_SIZE_HINT for quota-controlled files and do the necessary 230 // work before passing to the SQLite VFS. 231 if (op == SQLITE_FCNTL_SIZE_HINT && p->quotaObject) { 232 sqlite3_int64 hintSize = *static_cast<sqlite3_int64*>(pArg); 233 sqlite3_int64 currentSize; 234 rc = QuotaFileSize(pFile, ¤tSize); 235 if (rc != SQLITE_OK) { 236 return rc; 237 } 238 if (hintSize > currentSize) { 239 rc = QuotaTruncate(pFile, hintSize); 240 if (rc != SQLITE_OK) { 241 return rc; 242 } 243 } 244 } 245 rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg); 246 // Grab the file chunk size after the SQLite VFS has approved. 247 if (op == SQLITE_FCNTL_CHUNK_SIZE && rc == SQLITE_OK) { 248 p->fileChunkSize = *static_cast<int*>(pArg); 249 } 250 #ifdef DEBUG 251 if (op == SQLITE_FCNTL_SIZE_HINT && p->quotaObject && rc == SQLITE_OK) { 252 sqlite3_int64 hintSize = *static_cast<sqlite3_int64*>(pArg); 253 if (p->fileChunkSize > 0) { 254 hintSize = ((hintSize + p->fileChunkSize - 1) / p->fileChunkSize) * 255 p->fileChunkSize; 256 } 257 sqlite3_int64 currentSize; 258 MOZ_ASSERT(QuotaFileSize(pFile, ¤tSize) == SQLITE_OK); 259 MOZ_ASSERT(currentSize >= hintSize); 260 } 261 #endif 262 return rc; 263 } 264 265 /* 266 ** Return the sector-size in bytes for a QuotaFile. 267 */ 268 int QuotaSectorSize(sqlite3_file* pFile) { 269 QuotaFile* p = (QuotaFile*)pFile; 270 int rc; 271 rc = p->pReal->pMethods->xSectorSize(p->pReal); 272 return rc; 273 } 274 275 /* 276 ** Return the device characteristic flags supported by a QuotaFile. 277 */ 278 int QuotaDeviceCharacteristics(sqlite3_file* pFile) { 279 QuotaFile* p = (QuotaFile*)pFile; 280 int rc; 281 rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal); 282 return rc; 283 } 284 285 /* 286 ** Shared-memory operations. 287 */ 288 int QuotaShmLock(sqlite3_file* pFile, int ofst, int n, int flags) { 289 QuotaFile* p = (QuotaFile*)pFile; 290 return p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags); 291 } 292 293 int QuotaShmMap(sqlite3_file* pFile, int iRegion, int szRegion, int isWrite, 294 void volatile** pp) { 295 QuotaFile* p = (QuotaFile*)pFile; 296 int rc; 297 rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp); 298 return rc; 299 } 300 301 void QuotaShmBarrier(sqlite3_file* pFile) { 302 QuotaFile* p = (QuotaFile*)pFile; 303 p->pReal->pMethods->xShmBarrier(p->pReal); 304 } 305 306 int QuotaShmUnmap(sqlite3_file* pFile, int delFlag) { 307 QuotaFile* p = (QuotaFile*)pFile; 308 int rc; 309 rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag); 310 return rc; 311 } 312 313 int QuotaFetch(sqlite3_file* pFile, sqlite3_int64 iOff, int iAmt, void** pp) { 314 QuotaFile* p = (QuotaFile*)pFile; 315 MOZ_ASSERT(p->pReal->pMethods->iVersion >= 3); 316 return p->pReal->pMethods->xFetch(p->pReal, iOff, iAmt, pp); 317 } 318 319 int QuotaUnfetch(sqlite3_file* pFile, sqlite3_int64 iOff, void* pResOut) { 320 QuotaFile* p = (QuotaFile*)pFile; 321 MOZ_ASSERT(p->pReal->pMethods->iVersion >= 3); 322 return p->pReal->pMethods->xUnfetch(p->pReal, iOff, pResOut); 323 } 324 325 int QuotaOpen(sqlite3_vfs* vfs, const char* zName, sqlite3_file* pFile, 326 int flags, int* pOutFlags) { 327 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 328 int rc; 329 QuotaFile* p = (QuotaFile*)pFile; 330 331 MaybeEstablishQuotaControl(zName, p, flags); 332 333 rc = orig_vfs->xOpen(orig_vfs, zName, p->pReal, flags, pOutFlags); 334 if (rc != SQLITE_OK) return rc; 335 if (p->pReal->pMethods) { 336 sqlite3_io_methods* pNew = new sqlite3_io_methods; 337 const sqlite3_io_methods* pSub = p->pReal->pMethods; 338 memset(pNew, 0, sizeof(*pNew)); 339 // If the io_methods version is higher than the last known one, you should 340 // update this VFS adding appropriate IO methods for any methods added in 341 // the version change. 342 pNew->iVersion = pSub->iVersion; 343 MOZ_ASSERT(pNew->iVersion <= LAST_KNOWN_IOMETHODS_VERSION); 344 pNew->xClose = QuotaClose; 345 pNew->xRead = QuotaRead; 346 pNew->xWrite = QuotaWrite; 347 pNew->xTruncate = QuotaTruncate; 348 pNew->xSync = QuotaSync; 349 pNew->xFileSize = QuotaFileSize; 350 pNew->xLock = QuotaLock; 351 pNew->xUnlock = QuotaUnlock; 352 pNew->xCheckReservedLock = QuotaCheckReservedLock; 353 pNew->xFileControl = QuotaFileControl; 354 pNew->xSectorSize = QuotaSectorSize; 355 pNew->xDeviceCharacteristics = QuotaDeviceCharacteristics; 356 if (pNew->iVersion >= 2) { 357 // Methods added in version 2. 358 pNew->xShmMap = pSub->xShmMap ? QuotaShmMap : nullptr; 359 pNew->xShmLock = pSub->xShmLock ? QuotaShmLock : nullptr; 360 pNew->xShmBarrier = pSub->xShmBarrier ? QuotaShmBarrier : nullptr; 361 pNew->xShmUnmap = pSub->xShmUnmap ? QuotaShmUnmap : nullptr; 362 } 363 if (pNew->iVersion >= 3) { 364 // Methods added in version 3. 365 // SQLite 3.7.17 calls these methods without checking for nullptr first, 366 // so we always define them. Verify that we're not going to call 367 // nullptrs, though. 368 MOZ_ASSERT(pSub->xFetch); 369 pNew->xFetch = QuotaFetch; 370 MOZ_ASSERT(pSub->xUnfetch); 371 pNew->xUnfetch = QuotaUnfetch; 372 } 373 pFile->pMethods = pNew; 374 } 375 return rc; 376 } 377 378 int QuotaDelete(sqlite3_vfs* vfs, const char* zName, int syncDir) { 379 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 380 int rc; 381 RefPtr<QuotaObject> quotaObject; 382 383 if (StringEndsWith(nsDependentCString(zName), "-wal"_ns)) { 384 quotaObject = GetQuotaObjectFromName(zName); 385 } 386 387 rc = orig_vfs->xDelete(orig_vfs, zName, syncDir); 388 if (rc == SQLITE_OK && quotaObject) { 389 MOZ_ALWAYS_TRUE(quotaObject->MaybeUpdateSize(0, /* aTruncate */ true)); 390 } 391 392 return rc; 393 } 394 395 int QuotaAccess(sqlite3_vfs* vfs, const char* zName, int flags, int* pResOut) { 396 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 397 return orig_vfs->xAccess(orig_vfs, zName, flags, pResOut); 398 } 399 400 int QuotaFullPathname(sqlite3_vfs* vfs, const char* zName, int nOut, 401 char* zOut) { 402 #if defined(XP_WIN) 403 // SQLite uses GetFullPathnameW which also normailizes file path. If a file 404 // component ends with a dot, it would be removed. However, it's not desired. 405 // 406 // And that would result SQLite uses wrong database and quotaObject. 407 // Note that we are safe to avoid the GetFullPathnameW call for \\?\ prefixed 408 // paths. 409 // And note that this hack will be removed once the issue is fixed directly in 410 // SQLite. 411 412 // zName that starts with "//?/" is the case when a file URI was passed and 413 // zName that starts with "\\?\" is the case when a normal path was passed 414 // (not file URI). 415 if (StaticPrefs::dom_quotaManager_overrideXFullPathname() && 416 ((zName[0] == '/' && zName[1] == '/' && zName[2] == '?' && 417 zName[3] == '/') || 418 (zName[0] == '\\' && zName[1] == '\\' && zName[2] == '?' && 419 zName[3] == '\\'))) { 420 MOZ_ASSERT(nOut >= vfs->mxPathname); 421 MOZ_ASSERT(static_cast<size_t>(nOut) > strlen(zName)); 422 423 size_t index = 0; 424 while (zName[index] != '\0') { 425 if (zName[index] == '/') { 426 zOut[index] = '\\'; 427 } else { 428 zOut[index] = zName[index]; 429 } 430 431 index++; 432 } 433 zOut[index] = '\0'; 434 435 return SQLITE_OK; 436 } 437 #elif defined(XP_UNIX) 438 // SQLite canonicalizes (resolves path components) file paths on Unix which 439 // doesn't work well with file path sanity checks in quota manager. This is 440 // especially a problem on mac where /var is a symlink to /private/var. 441 // Since QuotaVFS is used only by quota clients which never access databases 442 // outside of PROFILE/storage, we override Unix xFullPathname with own 443 // implementation that doesn't do any canonicalization. 444 445 if (StaticPrefs::dom_quotaManager_overrideXFullPathnameUnix()) { 446 if (nOut < 0) { 447 // Match the return code used by SQLite's xFullPathname implementation 448 // here and below. 449 return SQLITE_CANTOPEN; 450 } 451 452 QM_TRY_INSPECT( 453 const auto& path, ([&zName]() -> Result<nsString, nsresult> { 454 NS_ConvertUTF8toUTF16 name(zName); 455 456 if (name.First() == '/') { 457 return std::move(name); 458 } 459 460 QM_TRY_INSPECT(const auto& file, 461 MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<nsIFile>, 462 NS_GetSpecialDirectory, 463 NS_OS_CURRENT_WORKING_DIR)); 464 465 QM_TRY(MOZ_TO_RESULT(file->Append(name))); 466 467 QM_TRY_RETURN( 468 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString, file, GetPath)); 469 }()), 470 SQLITE_CANTOPEN); 471 472 QM_TRY_INSPECT(const auto& quotaFile, QM_NewLocalFile(path), 473 SQLITE_CANTOPEN); 474 475 QM_TRY_INSPECT( 476 const auto& quotaPath, 477 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString, quotaFile, GetPath), 478 SQLITE_CANTOPEN); 479 480 NS_ConvertUTF16toUTF8 sqlitePath(quotaPath); 481 482 if (sqlitePath.Length() > (unsigned int)nOut) { 483 return SQLITE_CANTOPEN; 484 } 485 486 nsCharTraits<char>::copy(zOut, sqlitePath.get(), sqlitePath.Length()); 487 zOut[sqlitePath.Length()] = '\0'; 488 489 return SQLITE_OK; 490 } 491 #endif 492 493 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 494 return orig_vfs->xFullPathname(orig_vfs, zName, nOut, zOut); 495 } 496 497 void* QuotaDlOpen(sqlite3_vfs* vfs, const char* zFilename) { 498 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 499 return orig_vfs->xDlOpen(orig_vfs, zFilename); 500 } 501 502 void QuotaDlError(sqlite3_vfs* vfs, int nByte, char* zErrMsg) { 503 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 504 orig_vfs->xDlError(orig_vfs, nByte, zErrMsg); 505 } 506 507 void (*QuotaDlSym(sqlite3_vfs* vfs, void* pHdle, const char* zSym))(void) { 508 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 509 return orig_vfs->xDlSym(orig_vfs, pHdle, zSym); 510 } 511 512 void QuotaDlClose(sqlite3_vfs* vfs, void* pHandle) { 513 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 514 orig_vfs->xDlClose(orig_vfs, pHandle); 515 } 516 517 int QuotaRandomness(sqlite3_vfs* vfs, int nByte, char* zOut) { 518 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 519 return orig_vfs->xRandomness(orig_vfs, nByte, zOut); 520 } 521 522 int QuotaSleep(sqlite3_vfs* vfs, int microseconds) { 523 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 524 return orig_vfs->xSleep(orig_vfs, microseconds); 525 } 526 527 int QuotaCurrentTime(sqlite3_vfs* vfs, double* prNow) { 528 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 529 return orig_vfs->xCurrentTime(orig_vfs, prNow); 530 } 531 532 int QuotaGetLastError(sqlite3_vfs* vfs, int nBuf, char* zBuf) { 533 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 534 return orig_vfs->xGetLastError(orig_vfs, nBuf, zBuf); 535 } 536 537 int QuotaCurrentTimeInt64(sqlite3_vfs* vfs, sqlite3_int64* piNow) { 538 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 539 return orig_vfs->xCurrentTimeInt64(orig_vfs, piNow); 540 } 541 542 static int QuotaSetSystemCall(sqlite3_vfs* vfs, const char* zName, 543 sqlite3_syscall_ptr pFunc) { 544 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 545 return orig_vfs->xSetSystemCall(orig_vfs, zName, pFunc); 546 } 547 548 static sqlite3_syscall_ptr QuotaGetSystemCall(sqlite3_vfs* vfs, 549 const char* zName) { 550 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 551 return orig_vfs->xGetSystemCall(orig_vfs, zName); 552 } 553 554 static const char* QuotaNextSystemCall(sqlite3_vfs* vfs, const char* zName) { 555 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 556 return orig_vfs->xNextSystemCall(orig_vfs, zName); 557 } 558 559 } // namespace 560 561 namespace mozilla::storage::quotavfs { 562 563 const char* GetVFSName() { return "quotavfs"; } 564 565 UniquePtr<sqlite3_vfs> ConstructVFS(const char* aBaseVFSName) { 566 MOZ_ASSERT(aBaseVFSName); 567 568 if (sqlite3_vfs_find(GetVFSName()) != nullptr) { 569 return nullptr; 570 } 571 sqlite3_vfs* vfs = sqlite3_vfs_find(aBaseVFSName); 572 if (!vfs) { 573 return nullptr; 574 } 575 576 auto qvfs = MakeUnique<sqlite3_vfs>(); 577 memset(qvfs.get(), 0, sizeof(::sqlite3_vfs)); 578 // If the VFS version is higher than the last known one, you should update 579 // this VFS adding appropriate methods for any methods added in the version 580 // change. 581 qvfs->iVersion = vfs->iVersion; 582 MOZ_ASSERT(vfs->iVersion <= LAST_KNOWN_VFS_VERSION); 583 qvfs->szOsFile = static_cast<int>(sizeof(QuotaFile) - sizeof(sqlite3_file) + 584 vfs->szOsFile); 585 qvfs->mxPathname = vfs->mxPathname; 586 qvfs->zName = GetVFSName(); 587 qvfs->pAppData = vfs; 588 qvfs->xOpen = QuotaOpen; 589 qvfs->xDelete = QuotaDelete; 590 qvfs->xAccess = QuotaAccess; 591 qvfs->xFullPathname = QuotaFullPathname; 592 qvfs->xDlOpen = QuotaDlOpen; 593 qvfs->xDlError = QuotaDlError; 594 qvfs->xDlSym = QuotaDlSym; 595 qvfs->xDlClose = QuotaDlClose; 596 qvfs->xRandomness = QuotaRandomness; 597 qvfs->xSleep = QuotaSleep; 598 qvfs->xCurrentTime = QuotaCurrentTime; 599 qvfs->xGetLastError = QuotaGetLastError; 600 if (qvfs->iVersion >= 2) { 601 // Methods added in version 2. 602 qvfs->xCurrentTimeInt64 = QuotaCurrentTimeInt64; 603 } 604 if (qvfs->iVersion >= 3) { 605 // Methods added in version 3. 606 qvfs->xSetSystemCall = QuotaSetSystemCall; 607 qvfs->xGetSystemCall = QuotaGetSystemCall; 608 qvfs->xNextSystemCall = QuotaNextSystemCall; 609 } 610 return qvfs; 611 } 612 613 already_AddRefed<QuotaObject> GetQuotaObjectForFile(sqlite3_file* pFile) { 614 MOZ_ASSERT(pFile); 615 616 QuotaFile* p = (QuotaFile*)pFile; 617 RefPtr<QuotaObject> result = p->quotaObject; 618 return result.forget(); 619 } 620 621 } // namespace mozilla::storage::quotavfs