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/. */
8 #include "mozilla/dom/quota/PersistenceType.h"
9 #include "mozilla/dom/quota/QuotaManager.h"
10 #include "mozilla/dom/quota/QuotaObject.h"
11 #include "mozilla/dom/quota/ResultExtensions.h"
12 #include "nsDirectoryServiceDefs.h"
14 #include "mozilla/StaticPrefs_storage.h"
16 #if defined(XP_WIN) || defined(XP_UNIX)
17 # include "mozilla/StaticPrefs_dom.h"
20 // The last VFS version for which this file has been updated.
21 #define LAST_KNOWN_VFS_VERSION 3
23 // The last io_methods version for which this file has been updated.
24 #define LAST_KNOWN_IOMETHODS_VERSION 3
28 using namespace mozilla
;
29 using namespace mozilla::dom::quota
;
32 // Base class. Must be first
35 // quota object for this file
36 RefPtr
<QuotaObject
> quotaObject
;
38 // The chunk size for this file. See the documentation for
39 // sqlite3_file_control() and FCNTL_CHUNK_SIZE.
42 // This contains the vfs that actually does work
43 sqlite3_file pReal
[1];
46 already_AddRefed
<QuotaObject
> GetQuotaObjectFromName(const char* zName
) {
49 const char* directoryLockIdParam
=
50 sqlite3_uri_parameter(zName
, "directoryLockId");
51 if (!directoryLockIdParam
) {
56 const int64_t directoryLockId
=
57 nsDependentCString(directoryLockIdParam
).ToInteger64(&rv
);
58 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv
));
60 QuotaManager
* quotaManager
= QuotaManager::Get();
61 MOZ_ASSERT(quotaManager
);
63 return quotaManager
->GetQuotaObject(directoryLockId
,
64 NS_ConvertUTF8toUTF16(zName
));
67 void MaybeEstablishQuotaControl(const char* zName
, QuotaFile
* pFile
,
70 MOZ_ASSERT(!pFile
->quotaObject
);
72 if (!(flags
& (SQLITE_OPEN_URI
| SQLITE_OPEN_WAL
))) {
75 pFile
->quotaObject
= GetQuotaObjectFromName(zName
);
81 int QuotaClose(sqlite3_file
* pFile
) {
82 QuotaFile
* p
= (QuotaFile
*)pFile
;
84 rc
= p
->pReal
->pMethods
->xClose(p
->pReal
);
85 if (rc
== SQLITE_OK
) {
86 delete p
->base
.pMethods
;
87 p
->base
.pMethods
= nullptr;
88 p
->quotaObject
= nullptr;
97 ** Read data from a QuotaFile.
99 int QuotaRead(sqlite3_file
* pFile
, void* zBuf
, int iAmt
, sqlite_int64 iOfst
) {
100 QuotaFile
* p
= (QuotaFile
*)pFile
;
102 rc
= p
->pReal
->pMethods
->xRead(p
->pReal
, zBuf
, iAmt
, iOfst
);
107 ** Return the current file-size of a QuotaFile.
109 int QuotaFileSize(sqlite3_file
* pFile
, sqlite_int64
* pSize
) {
110 QuotaFile
* p
= (QuotaFile
*)pFile
;
112 rc
= p
->pReal
->pMethods
->xFileSize(p
->pReal
, pSize
);
117 ** Write data to a QuotaFile.
119 int QuotaWrite(sqlite3_file
* pFile
, const void* zBuf
, int iAmt
,
120 sqlite_int64 iOfst
) {
121 QuotaFile
* p
= (QuotaFile
*)pFile
;
123 if (p
->quotaObject
) {
124 MOZ_ASSERT(INT64_MAX
- iOfst
>= iAmt
);
125 if (!p
->quotaObject
->MaybeUpdateSize(iOfst
+ iAmt
, /* aTruncate */ false)) {
129 rc
= p
->pReal
->pMethods
->xWrite(p
->pReal
, zBuf
, iAmt
, iOfst
);
130 if (p
->quotaObject
&& rc
!= SQLITE_OK
) {
132 "xWrite failed on a quota-controlled file, attempting to "
133 "update its current size...");
134 sqlite_int64 currentSize
;
135 if (QuotaFileSize(pFile
, ¤tSize
) == SQLITE_OK
) {
136 DebugOnly
<bool> res
=
137 p
->quotaObject
->MaybeUpdateSize(currentSize
, /* aTruncate */ true);
145 ** Truncate a QuotaFile.
147 int QuotaTruncate(sqlite3_file
* pFile
, sqlite_int64 size
) {
148 QuotaFile
* p
= (QuotaFile
*)pFile
;
150 if (p
->quotaObject
) {
151 if (p
->fileChunkSize
> 0) {
152 // Round up to the smallest multiple of the chunk size that will hold all
155 ((size
+ p
->fileChunkSize
- 1) / p
->fileChunkSize
) * p
->fileChunkSize
;
157 if (!p
->quotaObject
->MaybeUpdateSize(size
, /* aTruncate */ true)) {
161 rc
= p
->pReal
->pMethods
->xTruncate(p
->pReal
, size
);
162 if (p
->quotaObject
) {
163 if (rc
== SQLITE_OK
) {
165 // Make sure xTruncate set the size exactly as we calculated above.
166 sqlite_int64 newSize
;
167 MOZ_ASSERT(QuotaFileSize(pFile
, &newSize
) == SQLITE_OK
);
168 MOZ_ASSERT(newSize
== size
);
172 "xTruncate failed on a quota-controlled file, attempting to "
173 "update its current size...");
174 if (QuotaFileSize(pFile
, &size
) == SQLITE_OK
) {
175 DebugOnly
<bool> res
=
176 p
->quotaObject
->MaybeUpdateSize(size
, /* aTruncate */ true);
187 int QuotaSync(sqlite3_file
* pFile
, int flags
) {
188 QuotaFile
* p
= (QuotaFile
*)pFile
;
189 return p
->pReal
->pMethods
->xSync(p
->pReal
, flags
);
195 int QuotaLock(sqlite3_file
* pFile
, int eLock
) {
196 QuotaFile
* p
= (QuotaFile
*)pFile
;
198 rc
= p
->pReal
->pMethods
->xLock(p
->pReal
, eLock
);
203 ** Unlock a QuotaFile.
205 int QuotaUnlock(sqlite3_file
* pFile
, int eLock
) {
206 QuotaFile
* p
= (QuotaFile
*)pFile
;
208 rc
= p
->pReal
->pMethods
->xUnlock(p
->pReal
, eLock
);
213 ** Check if another file-handle holds a RESERVED lock on a QuotaFile.
215 int QuotaCheckReservedLock(sqlite3_file
* pFile
, int* pResOut
) {
216 QuotaFile
* p
= (QuotaFile
*)pFile
;
217 int rc
= p
->pReal
->pMethods
->xCheckReservedLock(p
->pReal
, pResOut
);
222 ** File control method. For custom operations on a QuotaFile.
224 int QuotaFileControl(sqlite3_file
* pFile
, int op
, void* pArg
) {
225 QuotaFile
* p
= (QuotaFile
*)pFile
;
227 // Hook SQLITE_FCNTL_SIZE_HINT for quota-controlled files and do the necessary
228 // work before passing to the SQLite VFS.
229 if (op
== SQLITE_FCNTL_SIZE_HINT
&& p
->quotaObject
) {
230 sqlite3_int64 hintSize
= *static_cast<sqlite3_int64
*>(pArg
);
231 sqlite3_int64 currentSize
;
232 rc
= QuotaFileSize(pFile
, ¤tSize
);
233 if (rc
!= SQLITE_OK
) {
236 if (hintSize
> currentSize
) {
237 rc
= QuotaTruncate(pFile
, hintSize
);
238 if (rc
!= SQLITE_OK
) {
243 rc
= p
->pReal
->pMethods
->xFileControl(p
->pReal
, op
, pArg
);
244 // Grab the file chunk size after the SQLite VFS has approved.
245 if (op
== SQLITE_FCNTL_CHUNK_SIZE
&& rc
== SQLITE_OK
) {
246 p
->fileChunkSize
= *static_cast<int*>(pArg
);
249 if (op
== SQLITE_FCNTL_SIZE_HINT
&& p
->quotaObject
&& rc
== SQLITE_OK
) {
250 sqlite3_int64 hintSize
= *static_cast<sqlite3_int64
*>(pArg
);
251 if (p
->fileChunkSize
> 0) {
252 hintSize
= ((hintSize
+ p
->fileChunkSize
- 1) / p
->fileChunkSize
) *
255 sqlite3_int64 currentSize
;
256 MOZ_ASSERT(QuotaFileSize(pFile
, ¤tSize
) == SQLITE_OK
);
257 MOZ_ASSERT(currentSize
>= hintSize
);
264 ** Return the sector-size in bytes for a QuotaFile.
266 int QuotaSectorSize(sqlite3_file
* pFile
) {
267 QuotaFile
* p
= (QuotaFile
*)pFile
;
269 rc
= p
->pReal
->pMethods
->xSectorSize(p
->pReal
);
274 ** Return the device characteristic flags supported by a QuotaFile.
276 int QuotaDeviceCharacteristics(sqlite3_file
* pFile
) {
277 QuotaFile
* p
= (QuotaFile
*)pFile
;
279 rc
= p
->pReal
->pMethods
->xDeviceCharacteristics(p
->pReal
);
284 ** Shared-memory operations.
286 int QuotaShmLock(sqlite3_file
* pFile
, int ofst
, int n
, int flags
) {
287 QuotaFile
* p
= (QuotaFile
*)pFile
;
288 return p
->pReal
->pMethods
->xShmLock(p
->pReal
, ofst
, n
, flags
);
291 int QuotaShmMap(sqlite3_file
* pFile
, int iRegion
, int szRegion
, int isWrite
,
292 void volatile** pp
) {
293 QuotaFile
* p
= (QuotaFile
*)pFile
;
295 rc
= p
->pReal
->pMethods
->xShmMap(p
->pReal
, iRegion
, szRegion
, isWrite
, pp
);
299 void QuotaShmBarrier(sqlite3_file
* pFile
) {
300 QuotaFile
* p
= (QuotaFile
*)pFile
;
301 p
->pReal
->pMethods
->xShmBarrier(p
->pReal
);
304 int QuotaShmUnmap(sqlite3_file
* pFile
, int delFlag
) {
305 QuotaFile
* p
= (QuotaFile
*)pFile
;
307 rc
= p
->pReal
->pMethods
->xShmUnmap(p
->pReal
, delFlag
);
311 int QuotaFetch(sqlite3_file
* pFile
, sqlite3_int64 iOff
, int iAmt
, void** pp
) {
312 QuotaFile
* p
= (QuotaFile
*)pFile
;
313 MOZ_ASSERT(p
->pReal
->pMethods
->iVersion
>= 3);
314 return p
->pReal
->pMethods
->xFetch(p
->pReal
, iOff
, iAmt
, pp
);
317 int QuotaUnfetch(sqlite3_file
* pFile
, sqlite3_int64 iOff
, void* pResOut
) {
318 QuotaFile
* p
= (QuotaFile
*)pFile
;
319 MOZ_ASSERT(p
->pReal
->pMethods
->iVersion
>= 3);
320 return p
->pReal
->pMethods
->xUnfetch(p
->pReal
, iOff
, pResOut
);
323 int QuotaOpen(sqlite3_vfs
* vfs
, const char* zName
, sqlite3_file
* pFile
,
324 int flags
, int* pOutFlags
) {
325 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
327 QuotaFile
* p
= (QuotaFile
*)pFile
;
329 MaybeEstablishQuotaControl(zName
, p
, flags
);
331 rc
= orig_vfs
->xOpen(orig_vfs
, zName
, p
->pReal
, flags
, pOutFlags
);
332 if (rc
!= SQLITE_OK
) return rc
;
333 if (p
->pReal
->pMethods
) {
334 sqlite3_io_methods
* pNew
= new sqlite3_io_methods
;
335 const sqlite3_io_methods
* pSub
= p
->pReal
->pMethods
;
336 memset(pNew
, 0, sizeof(*pNew
));
337 // If the io_methods version is higher than the last known one, you should
338 // update this VFS adding appropriate IO methods for any methods added in
339 // the version change.
340 pNew
->iVersion
= pSub
->iVersion
;
341 MOZ_ASSERT(pNew
->iVersion
<= LAST_KNOWN_IOMETHODS_VERSION
);
342 pNew
->xClose
= QuotaClose
;
343 pNew
->xRead
= QuotaRead
;
344 pNew
->xWrite
= QuotaWrite
;
345 pNew
->xTruncate
= QuotaTruncate
;
346 pNew
->xSync
= QuotaSync
;
347 pNew
->xFileSize
= QuotaFileSize
;
348 pNew
->xLock
= QuotaLock
;
349 pNew
->xUnlock
= QuotaUnlock
;
350 pNew
->xCheckReservedLock
= QuotaCheckReservedLock
;
351 pNew
->xFileControl
= QuotaFileControl
;
352 pNew
->xSectorSize
= QuotaSectorSize
;
353 pNew
->xDeviceCharacteristics
= QuotaDeviceCharacteristics
;
354 if (pNew
->iVersion
>= 2) {
355 // Methods added in version 2.
356 pNew
->xShmMap
= pSub
->xShmMap
? QuotaShmMap
: nullptr;
357 pNew
->xShmLock
= pSub
->xShmLock
? QuotaShmLock
: nullptr;
358 pNew
->xShmBarrier
= pSub
->xShmBarrier
? QuotaShmBarrier
: nullptr;
359 pNew
->xShmUnmap
= pSub
->xShmUnmap
? QuotaShmUnmap
: nullptr;
361 if (pNew
->iVersion
>= 3) {
362 // Methods added in version 3.
363 // SQLite 3.7.17 calls these methods without checking for nullptr first,
364 // so we always define them. Verify that we're not going to call
366 MOZ_ASSERT(pSub
->xFetch
);
367 pNew
->xFetch
= QuotaFetch
;
368 MOZ_ASSERT(pSub
->xUnfetch
);
369 pNew
->xUnfetch
= QuotaUnfetch
;
371 pFile
->pMethods
= pNew
;
376 int QuotaDelete(sqlite3_vfs
* vfs
, const char* zName
, int syncDir
) {
377 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
379 RefPtr
<QuotaObject
> quotaObject
;
381 if (StringEndsWith(nsDependentCString(zName
), "-wal"_ns
)) {
382 quotaObject
= GetQuotaObjectFromName(zName
);
385 rc
= orig_vfs
->xDelete(orig_vfs
, zName
, syncDir
);
386 if (rc
== SQLITE_OK
&& quotaObject
) {
387 MOZ_ALWAYS_TRUE(quotaObject
->MaybeUpdateSize(0, /* aTruncate */ true));
393 int QuotaAccess(sqlite3_vfs
* vfs
, const char* zName
, int flags
, int* pResOut
) {
394 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
395 return orig_vfs
->xAccess(orig_vfs
, zName
, flags
, pResOut
);
398 int QuotaFullPathname(sqlite3_vfs
* vfs
, const char* zName
, int nOut
,
401 // SQLite uses GetFullPathnameW which also normailizes file path. If a file
402 // component ends with a dot, it would be removed. However, it's not desired.
404 // And that would result SQLite uses wrong database and quotaObject.
405 // Note that we are safe to avoid the GetFullPathnameW call for \\?\ prefixed
407 // And note that this hack will be removed once the issue is fixed directly in
410 // zName that starts with "//?/" is the case when a file URI was passed and
411 // zName that starts with "\\?\" is the case when a normal path was passed
413 if (StaticPrefs::dom_quotaManager_overrideXFullPathname() &&
414 ((zName
[0] == '/' && zName
[1] == '/' && zName
[2] == '?' &&
416 (zName
[0] == '\\' && zName
[1] == '\\' && zName
[2] == '?' &&
417 zName
[3] == '\\'))) {
418 MOZ_ASSERT(nOut
>= vfs
->mxPathname
);
419 MOZ_ASSERT(static_cast<size_t>(nOut
) > strlen(zName
));
422 while (zName
[index
] != '\0') {
423 if (zName
[index
] == '/') {
426 zOut
[index
] = zName
[index
];
435 #elif defined(XP_UNIX)
436 // SQLite canonicalizes (resolves path components) file paths on Unix which
437 // doesn't work well with file path sanity checks in quota manager. This is
438 // especially a problem on mac where /var is a symlink to /private/var.
439 // Since QuotaVFS is used only by quota clients which never access databases
440 // outside of PROFILE/storage, we override Unix xFullPathname with own
441 // implementation that doesn't do any canonicalization.
443 if (StaticPrefs::dom_quotaManager_overrideXFullPathnameUnix()) {
445 // Match the return code used by SQLite's xFullPathname implementation
447 return SQLITE_CANTOPEN
;
451 const auto& path
, ([&zName
]() -> Result
<nsString
, nsresult
> {
452 NS_ConvertUTF8toUTF16
name(zName
);
454 if (name
.First() == '/') {
455 return std::move(name
);
458 QM_TRY_INSPECT(const auto& file
,
459 MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr
<nsIFile
>,
460 NS_GetSpecialDirectory
,
461 NS_OS_CURRENT_WORKING_DIR
));
463 QM_TRY(MOZ_TO_RESULT(file
->Append(name
)));
466 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString
, file
, GetPath
));
470 QM_TRY_INSPECT(const auto& quotaFile
, QM_NewLocalFile(path
),
474 const auto& quotaPath
,
475 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString
, quotaFile
, GetPath
),
478 NS_ConvertUTF16toUTF8
sqlitePath(quotaPath
);
480 if (sqlitePath
.Length() > (unsigned int)nOut
) {
481 return SQLITE_CANTOPEN
;
484 nsCharTraits
<char>::copy(zOut
, sqlitePath
.get(), sqlitePath
.Length());
485 zOut
[sqlitePath
.Length()] = '\0';
491 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
492 return orig_vfs
->xFullPathname(orig_vfs
, zName
, nOut
, zOut
);
495 void* QuotaDlOpen(sqlite3_vfs
* vfs
, const char* zFilename
) {
496 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
497 return orig_vfs
->xDlOpen(orig_vfs
, zFilename
);
500 void QuotaDlError(sqlite3_vfs
* vfs
, int nByte
, char* zErrMsg
) {
501 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
502 orig_vfs
->xDlError(orig_vfs
, nByte
, zErrMsg
);
505 void (*QuotaDlSym(sqlite3_vfs
* vfs
, void* pHdle
, const char* zSym
))(void) {
506 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
507 return orig_vfs
->xDlSym(orig_vfs
, pHdle
, zSym
);
510 void QuotaDlClose(sqlite3_vfs
* vfs
, void* pHandle
) {
511 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
512 orig_vfs
->xDlClose(orig_vfs
, pHandle
);
515 int QuotaRandomness(sqlite3_vfs
* vfs
, int nByte
, char* zOut
) {
516 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
517 return orig_vfs
->xRandomness(orig_vfs
, nByte
, zOut
);
520 int QuotaSleep(sqlite3_vfs
* vfs
, int microseconds
) {
521 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
522 return orig_vfs
->xSleep(orig_vfs
, microseconds
);
525 int QuotaCurrentTime(sqlite3_vfs
* vfs
, double* prNow
) {
526 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
527 return orig_vfs
->xCurrentTime(orig_vfs
, prNow
);
530 int QuotaGetLastError(sqlite3_vfs
* vfs
, int nBuf
, char* zBuf
) {
531 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
532 return orig_vfs
->xGetLastError(orig_vfs
, nBuf
, zBuf
);
535 int QuotaCurrentTimeInt64(sqlite3_vfs
* vfs
, sqlite3_int64
* piNow
) {
536 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
537 return orig_vfs
->xCurrentTimeInt64(orig_vfs
, piNow
);
540 static int QuotaSetSystemCall(sqlite3_vfs
* vfs
, const char* zName
,
541 sqlite3_syscall_ptr pFunc
) {
542 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
543 return orig_vfs
->xSetSystemCall(orig_vfs
, zName
, pFunc
);
546 static sqlite3_syscall_ptr
QuotaGetSystemCall(sqlite3_vfs
* vfs
,
548 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
549 return orig_vfs
->xGetSystemCall(orig_vfs
, zName
);
552 static const char* QuotaNextSystemCall(sqlite3_vfs
* vfs
, const char* zName
) {
553 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
554 return orig_vfs
->xNextSystemCall(orig_vfs
, zName
);
562 const char* GetQuotaVFSName() { return "quotavfs"; }
564 UniquePtr
<sqlite3_vfs
> ConstructQuotaVFS(const char* aBaseVFSName
) {
565 MOZ_ASSERT(aBaseVFSName
);
567 if (sqlite3_vfs_find(GetQuotaVFSName()) != nullptr) {
570 sqlite3_vfs
* vfs
= sqlite3_vfs_find(aBaseVFSName
);
575 auto qvfs
= MakeUnique
<sqlite3_vfs
>();
576 memset(qvfs
.get(), 0, sizeof(::sqlite3_vfs
));
577 // If the VFS version is higher than the last known one, you should update
578 // this VFS adding appropriate methods for any methods added in the version
580 qvfs
->iVersion
= vfs
->iVersion
;
581 MOZ_ASSERT(vfs
->iVersion
<= LAST_KNOWN_VFS_VERSION
);
582 qvfs
->szOsFile
= static_cast<int>(sizeof(QuotaFile
) - sizeof(sqlite3_file
) +
584 qvfs
->mxPathname
= vfs
->mxPathname
;
585 qvfs
->zName
= GetQuotaVFSName();
586 qvfs
->pAppData
= vfs
;
587 qvfs
->xOpen
= QuotaOpen
;
588 qvfs
->xDelete
= QuotaDelete
;
589 qvfs
->xAccess
= QuotaAccess
;
590 qvfs
->xFullPathname
= QuotaFullPathname
;
591 qvfs
->xDlOpen
= QuotaDlOpen
;
592 qvfs
->xDlError
= QuotaDlError
;
593 qvfs
->xDlSym
= QuotaDlSym
;
594 qvfs
->xDlClose
= QuotaDlClose
;
595 qvfs
->xRandomness
= QuotaRandomness
;
596 qvfs
->xSleep
= QuotaSleep
;
597 qvfs
->xCurrentTime
= QuotaCurrentTime
;
598 qvfs
->xGetLastError
= QuotaGetLastError
;
599 if (qvfs
->iVersion
>= 2) {
600 // Methods added in version 2.
601 qvfs
->xCurrentTimeInt64
= QuotaCurrentTimeInt64
;
603 if (qvfs
->iVersion
>= 3) {
604 // Methods added in version 3.
605 qvfs
->xSetSystemCall
= QuotaSetSystemCall
;
606 qvfs
->xGetSystemCall
= QuotaGetSystemCall
;
607 qvfs
->xNextSystemCall
= QuotaNextSystemCall
;
612 already_AddRefed
<QuotaObject
> GetQuotaObjectForFile(sqlite3_file
* pFile
) {
615 QuotaFile
* p
= (QuotaFile
*)pFile
;
616 RefPtr
<QuotaObject
> result
= p
->quotaObject
;
617 return result
.forget();
620 } // namespace storage
621 } // namespace mozilla