Backed out changeset afdd9e4681c1 (bug 1932137) by developer request. CLOSED TREE
[gecko.git] / storage / QuotaVFS.cpp
blobb9490ff0d59b0c12c420e7a73afe4cfd42b9f556
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/. */
7 #include "QuotaVFS.h"
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"
18 #if defined(XP_WIN) || defined(XP_UNIX)
19 # include "mozilla/StaticPrefs_dom.h"
20 #endif
22 // The last VFS version for which this file has been updated.
23 #define LAST_KNOWN_VFS_VERSION 3
25 // The last io_methods version for which this file has been updated.
26 #define LAST_KNOWN_IOMETHODS_VERSION 3
28 namespace {
30 using namespace mozilla;
31 using namespace mozilla::dom::quota;
33 struct QuotaFile {
34 // Base class. Must be first
35 sqlite3_file base;
37 // quota object for this file
38 RefPtr<QuotaObject> quotaObject;
40 // The chunk size for this file. See the documentation for
41 // sqlite3_file_control() and FCNTL_CHUNK_SIZE.
42 int fileChunkSize;
44 // This contains the vfs that actually does work
45 sqlite3_file pReal[1];
48 already_AddRefed<QuotaObject> GetQuotaObjectFromName(const char* zName) {
49 MOZ_ASSERT(zName);
51 const char* directoryLockIdParam =
52 sqlite3_uri_parameter(zName, "directoryLockId");
53 if (!directoryLockIdParam) {
54 return nullptr;
57 nsresult rv;
58 const int64_t directoryLockId =
59 nsDependentCString(directoryLockIdParam).ToInteger64(&rv);
60 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
62 QuotaManager* quotaManager = QuotaManager::Get();
63 MOZ_ASSERT(quotaManager);
65 return quotaManager->GetQuotaObject(directoryLockId,
66 NS_ConvertUTF8toUTF16(zName));
69 void MaybeEstablishQuotaControl(const char* zName, QuotaFile* pFile,
70 int flags) {
71 MOZ_ASSERT(pFile);
72 MOZ_ASSERT(!pFile->quotaObject);
74 if (!(flags & (SQLITE_OPEN_URI | SQLITE_OPEN_WAL))) {
75 return;
77 pFile->quotaObject = GetQuotaObjectFromName(zName);
81 ** Close a QuotaFile.
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
95 return rc;
99 ** Read data from a QuotaFile.
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;
109 ** Return the current file-size of a QuotaFile.
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;
119 ** Write data to a QuotaFile.
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;
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, &currentSize) == SQLITE_OK) {
138 DebugOnly<bool> res =
139 p->quotaObject->MaybeUpdateSize(currentSize, /* aTruncate */ true);
140 MOZ_ASSERT(res);
143 return rc;
147 ** Truncate a QuotaFile.
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;
159 if (!p->quotaObject->MaybeUpdateSize(size, /* aTruncate */ true)) {
160 return SQLITE_FULL;
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);
183 return rc;
187 ** Sync a QuotaFile.
189 int QuotaSync(sqlite3_file* pFile, int flags) {
190 QuotaFile* p = (QuotaFile*)pFile;
191 return p->pReal->pMethods->xSync(p->pReal, flags);
195 ** Lock a QuotaFile.
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;
205 ** Unlock a QuotaFile.
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;
215 ** Check if another file-handle holds a RESERVED lock on a QuotaFile.
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;
224 ** File control method. For custom operations on a QuotaFile.
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, &currentSize);
235 if (rc != SQLITE_OK) {
236 return rc;
238 if (hintSize > currentSize) {
239 rc = QuotaTruncate(pFile, hintSize);
240 if (rc != SQLITE_OK) {
241 return rc;
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);
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;
257 sqlite3_int64 currentSize;
258 MOZ_ASSERT(QuotaFileSize(pFile, &currentSize) == SQLITE_OK);
259 MOZ_ASSERT(currentSize >= hintSize);
261 #endif
262 return rc;
266 ** Return the sector-size in bytes for a QuotaFile.
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;
276 ** Return the device characteristic flags supported by a QuotaFile.
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;
286 ** Shared-memory operations.
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);
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;
301 void QuotaShmBarrier(sqlite3_file* pFile) {
302 QuotaFile* p = (QuotaFile*)pFile;
303 p->pReal->pMethods->xShmBarrier(p->pReal);
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;
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);
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);
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;
331 MaybeEstablishQuotaControl(zName, p, flags);
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;
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;
373 pFile->pMethods = pNew;
375 return rc;
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;
383 if (StringEndsWith(nsDependentCString(zName), "-wal"_ns)) {
384 quotaObject = GetQuotaObjectFromName(zName);
387 rc = orig_vfs->xDelete(orig_vfs, zName, syncDir);
388 if (rc == SQLITE_OK && quotaObject) {
389 MOZ_ALWAYS_TRUE(quotaObject->MaybeUpdateSize(0, /* aTruncate */ true));
392 return rc;
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);
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.
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.
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));
423 size_t index = 0;
424 while (zName[index] != '\0') {
425 if (zName[index] == '/') {
426 zOut[index] = '\\';
427 } else {
428 zOut[index] = zName[index];
431 index++;
433 zOut[index] = '\0';
435 return SQLITE_OK;
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.
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;
452 QM_TRY_INSPECT(
453 const auto& path, ([&zName]() -> Result<nsString, nsresult> {
454 NS_ConvertUTF8toUTF16 name(zName);
456 if (name.First() == '/') {
457 return std::move(name);
460 QM_TRY_INSPECT(const auto& file,
461 MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<nsIFile>,
462 NS_GetSpecialDirectory,
463 NS_OS_CURRENT_WORKING_DIR));
465 QM_TRY(MOZ_TO_RESULT(file->Append(name)));
467 QM_TRY_RETURN(
468 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString, file, GetPath));
469 }()),
470 SQLITE_CANTOPEN);
472 QM_TRY_INSPECT(const auto& quotaFile, QM_NewLocalFile(path),
473 SQLITE_CANTOPEN);
475 QM_TRY_INSPECT(
476 const auto& quotaPath,
477 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString, quotaFile, GetPath),
478 SQLITE_CANTOPEN);
480 NS_ConvertUTF16toUTF8 sqlitePath(quotaPath);
482 if (sqlitePath.Length() > (unsigned int)nOut) {
483 return SQLITE_CANTOPEN;
486 nsCharTraits<char>::copy(zOut, sqlitePath.get(), sqlitePath.Length());
487 zOut[sqlitePath.Length()] = '\0';
489 return SQLITE_OK;
491 #endif
493 sqlite3_vfs* orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
494 return orig_vfs->xFullPathname(orig_vfs, zName, nOut, zOut);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
559 } // namespace
561 namespace mozilla::storage::quotavfs {
563 const char* GetVFSName() { return "quotavfs"; }
565 UniquePtr<sqlite3_vfs> ConstructVFS(const char* aBaseVFSName) {
566 MOZ_ASSERT(aBaseVFSName);
568 if (sqlite3_vfs_find(GetVFSName()) != nullptr) {
569 return nullptr;
571 sqlite3_vfs* vfs = sqlite3_vfs_find(aBaseVFSName);
572 if (!vfs) {
573 return nullptr;
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;
604 if (qvfs->iVersion >= 3) {
605 // Methods added in version 3.
606 qvfs->xSetSystemCall = QuotaSetSystemCall;
607 qvfs->xGetSystemCall = QuotaGetSystemCall;
608 qvfs->xNextSystemCall = QuotaNextSystemCall;
610 return qvfs;
613 already_AddRefed<QuotaObject> GetQuotaObjectForFile(sqlite3_file* pFile) {
614 MOZ_ASSERT(pFile);
616 QuotaFile* p = (QuotaFile*)pFile;
617 RefPtr<QuotaObject> result = p->quotaObject;
618 return result.forget();
621 } // namespace mozilla::storage::quotavfs