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/. */
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"
18 #if defined(XP_WIN) || defined(XP_UNIX)
19 # include "mozilla/StaticPrefs_dom.h"
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
30 using namespace mozilla
;
31 using namespace mozilla::dom::quota
;
34 // Base class. Must be first
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.
44 // This contains the vfs that actually does work
45 sqlite3_file pReal
[1];
48 already_AddRefed
<QuotaObject
> GetQuotaObjectFromName(const char* zName
) {
51 const char* directoryLockIdParam
=
52 sqlite3_uri_parameter(zName
, "directoryLockId");
53 if (!directoryLockIdParam
) {
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
,
72 MOZ_ASSERT(!pFile
->quotaObject
);
74 if (!(flags
& (SQLITE_OPEN_URI
| SQLITE_OPEN_WAL
))) {
77 pFile
->quotaObject
= GetQuotaObjectFromName(zName
);
83 int QuotaClose(sqlite3_file
* pFile
) {
84 QuotaFile
* p
= (QuotaFile
*)pFile
;
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;
99 ** Read data from a QuotaFile.
101 int QuotaRead(sqlite3_file
* pFile
, void* zBuf
, int iAmt
, sqlite_int64 iOfst
) {
102 QuotaFile
* p
= (QuotaFile
*)pFile
;
104 rc
= p
->pReal
->pMethods
->xRead(p
->pReal
, zBuf
, iAmt
, iOfst
);
109 ** Return the current file-size of a QuotaFile.
111 int QuotaFileSize(sqlite3_file
* pFile
, sqlite_int64
* pSize
) {
112 QuotaFile
* p
= (QuotaFile
*)pFile
;
114 rc
= p
->pReal
->pMethods
->xFileSize(p
->pReal
, pSize
);
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
;
125 if (p
->quotaObject
) {
126 MOZ_ASSERT(INT64_MAX
- iOfst
>= iAmt
);
127 if (!p
->quotaObject
->MaybeUpdateSize(iOfst
+ iAmt
, /* aTruncate */ false)) {
131 rc
= p
->pReal
->pMethods
->xWrite(p
->pReal
, zBuf
, iAmt
, iOfst
);
132 if (p
->quotaObject
&& rc
!= SQLITE_OK
) {
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);
147 ** Truncate a QuotaFile.
149 int QuotaTruncate(sqlite3_file
* pFile
, sqlite_int64 size
) {
150 QuotaFile
* p
= (QuotaFile
*)pFile
;
152 if (p
->quotaObject
) {
153 if (p
->fileChunkSize
> 0) {
154 // Round up to the smallest multiple of the chunk size that will hold all
157 ((size
+ p
->fileChunkSize
- 1) / p
->fileChunkSize
) * p
->fileChunkSize
;
159 if (!p
->quotaObject
->MaybeUpdateSize(size
, /* aTruncate */ true)) {
163 rc
= p
->pReal
->pMethods
->xTruncate(p
->pReal
, size
);
164 if (p
->quotaObject
) {
165 if (rc
== SQLITE_OK
) {
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
);
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);
189 int QuotaSync(sqlite3_file
* pFile
, int flags
) {
190 QuotaFile
* p
= (QuotaFile
*)pFile
;
191 return p
->pReal
->pMethods
->xSync(p
->pReal
, flags
);
197 int QuotaLock(sqlite3_file
* pFile
, int eLock
) {
198 QuotaFile
* p
= (QuotaFile
*)pFile
;
200 rc
= p
->pReal
->pMethods
->xLock(p
->pReal
, eLock
);
205 ** Unlock a QuotaFile.
207 int QuotaUnlock(sqlite3_file
* pFile
, int eLock
) {
208 QuotaFile
* p
= (QuotaFile
*)pFile
;
210 rc
= p
->pReal
->pMethods
->xUnlock(p
->pReal
, eLock
);
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
);
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
;
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
) {
238 if (hintSize
> currentSize
) {
239 rc
= QuotaTruncate(pFile
, hintSize
);
240 if (rc
!= SQLITE_OK
) {
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
);
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
) *
257 sqlite3_int64 currentSize
;
258 MOZ_ASSERT(QuotaFileSize(pFile
, ¤tSize
) == SQLITE_OK
);
259 MOZ_ASSERT(currentSize
>= hintSize
);
266 ** Return the sector-size in bytes for a QuotaFile.
268 int QuotaSectorSize(sqlite3_file
* pFile
) {
269 QuotaFile
* p
= (QuotaFile
*)pFile
;
271 rc
= p
->pReal
->pMethods
->xSectorSize(p
->pReal
);
276 ** Return the device characteristic flags supported by a QuotaFile.
278 int QuotaDeviceCharacteristics(sqlite3_file
* pFile
) {
279 QuotaFile
* p
= (QuotaFile
*)pFile
;
281 rc
= p
->pReal
->pMethods
->xDeviceCharacteristics(p
->pReal
);
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
;
297 rc
= p
->pReal
->pMethods
->xShmMap(p
->pReal
, iRegion
, szRegion
, isWrite
, pp
);
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
;
309 rc
= p
->pReal
->pMethods
->xShmUnmap(p
->pReal
, delFlag
);
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
);
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
368 MOZ_ASSERT(pSub
->xFetch
);
369 pNew
->xFetch
= QuotaFetch
;
370 MOZ_ASSERT(pSub
->xUnfetch
);
371 pNew
->xUnfetch
= QuotaUnfetch
;
373 pFile
->pMethods
= pNew
;
378 int QuotaDelete(sqlite3_vfs
* vfs
, const char* zName
, int syncDir
) {
379 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
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));
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
,
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
409 // And note that this hack will be removed once the issue is fixed directly in
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
415 if (StaticPrefs::dom_quotaManager_overrideXFullPathname() &&
416 ((zName
[0] == '/' && zName
[1] == '/' && zName
[2] == '?' &&
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
));
424 while (zName
[index
] != '\0') {
425 if (zName
[index
] == '/') {
428 zOut
[index
] = zName
[index
];
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()) {
447 // Match the return code used by SQLite's xFullPathname implementation
449 return SQLITE_CANTOPEN
;
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
)));
468 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString
, file
, GetPath
));
472 QM_TRY_INSPECT(const auto& quotaFile
, QM_NewLocalFile(path
),
476 const auto& quotaPath
,
477 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString
, quotaFile
, GetPath
),
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';
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
,
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
);
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) {
571 sqlite3_vfs
* vfs
= sqlite3_vfs_find(aBaseVFSName
);
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
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
) +
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
;
613 already_AddRefed
<QuotaObject
> GetQuotaObjectForFile(sqlite3_file
* pFile
) {
616 QuotaFile
* p
= (QuotaFile
*)pFile
;
617 RefPtr
<QuotaObject
> result
= p
->quotaObject
;
618 return result
.forget();
621 } // namespace mozilla::storage::quotavfs