tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

QuotaClient.cpp (19654B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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 "DBAction.h"
      8 #include "FileUtilsImpl.h"
      9 #include "QuotaClientImpl.h"
     10 #include "mozilla/GeckoTrace.h"
     11 #include "mozilla/ResultExtensions.h"
     12 #include "mozilla/dom/cache/DBSchema.h"
     13 #include "mozilla/dom/cache/Manager.h"
     14 #include "mozilla/dom/quota/PersistenceType.h"
     15 #include "mozilla/dom/quota/QuotaCommon.h"
     16 #include "mozilla/dom/quota/QuotaManager.h"
     17 #include "mozilla/dom/quota/UsageInfo.h"
     18 #include "mozilla/ipc/BackgroundParent.h"
     19 #include "nsIFile.h"
     20 #include "nsThreadUtils.h"
     21 
     22 namespace mozilla::dom::cache {
     23 
     24 using mozilla::dom::quota::AssertIsOnIOThread;
     25 using mozilla::dom::quota::Client;
     26 using mozilla::dom::quota::CloneFileAndAppend;
     27 using mozilla::dom::quota::DatabaseUsageType;
     28 using mozilla::dom::quota::GetDirEntryKind;
     29 using mozilla::dom::quota::nsIFileKind;
     30 using mozilla::dom::quota::OriginMetadata;
     31 using mozilla::dom::quota::PrincipalMetadata;
     32 using mozilla::dom::quota::QuotaManager;
     33 using mozilla::dom::quota::UsageInfo;
     34 using mozilla::ipc::AssertIsOnBackgroundThread;
     35 
     36 namespace {
     37 
     38 template <typename StepFunc>
     39 Result<UsageInfo, nsresult> ReduceUsageInfo(nsIFile& aDir,
     40                                            const Atomic<bool>& aCanceled,
     41                                            const StepFunc& aStepFunc) {
     42  QM_TRY_RETURN(quota::ReduceEachFileAtomicCancelable(
     43      aDir, aCanceled, UsageInfo{},
     44      [&aStepFunc](UsageInfo usageInfo, const nsCOMPtr<nsIFile>& bodyDir)
     45          -> Result<UsageInfo, nsresult> {
     46        QM_TRY(OkIf(!QuotaManager::IsShuttingDown()).mapErr([](const auto&) {
     47          return NS_ERROR_ABORT;
     48        }));
     49 
     50        QM_TRY_INSPECT(const auto& stepUsageInfo, aStepFunc(bodyDir));
     51 
     52        return usageInfo + stepUsageInfo;
     53      }));
     54 }
     55 
     56 Result<int64_t, nsresult> GetPaddingSizeFromDB(
     57    nsIFile& aDir, nsIFile& aDBFile, const OriginMetadata& aOriginMetadata,
     58    const Maybe<CipherKey>& aMaybeCipherKey) {
     59  CacheDirectoryMetadata directoryMetadata(aOriginMetadata);
     60  // directoryMetadata.mDirectoryLockId must be -1 (which is default for new
     61  // CacheDirectoryMetadata) because this method should only be called from
     62  // QuotaClient::InitOrigin when the temporary storage hasn't been initialized
     63  // yet. At that time, the in-memory objects (e.g. OriginInfo) are only being
     64  // created so it doesn't make sense to tunnel quota information to QuotaVFS
     65  // to get corresponding QuotaObject instance for the SQLite file).
     66  MOZ_DIAGNOSTIC_ASSERT(directoryMetadata.mDirectoryLockId == -1);
     67 
     68 #ifdef DEBUG
     69  {
     70    QM_TRY_INSPECT(const bool& exists,
     71                   MOZ_TO_RESULT_INVOKE_MEMBER(aDBFile, Exists));
     72    MOZ_ASSERT(exists);
     73  }
     74 #endif
     75 
     76  QM_TRY_INSPECT(const auto& conn,
     77                 OpenDBConnection(directoryMetadata, aDBFile, aMaybeCipherKey));
     78 
     79  // Make sure that the database has the latest schema before we try to read
     80  // from it. We have to do this because GetPaddingSizeFromDB is called
     81  // by InitOrigin. And it means that SetupAction::RunSyncWithDBOnTarget hasn't
     82  // checked the schema for the given origin yet).
     83  QM_TRY(MOZ_TO_RESULT(db::CreateOrMigrateSchema(aDir, *conn)));
     84 
     85  QM_TRY_RETURN(DirectoryPaddingRestore(aDir, *conn,
     86                                        /* aMustRestore */ false));
     87 }
     88 
     89 Result<int64_t, nsresult> GetTotalDiskUsageFromDB(
     90    nsIFile& aDir, nsIFile& aDBFile, const OriginMetadata& aOriginMetadata,
     91    const Maybe<CipherKey>& aMaybeCipherKey) {
     92  CacheDirectoryMetadata directoryMetadata(aOriginMetadata);
     93  // directoryMetadata.mDirectoryLockId must be -1 (which is default for new
     94  // CacheDirectoryMetadata) because this method should only be called from
     95  // QuotaClient::InitOrigin when the temporary storage hasn't been initialized
     96  // yet. At that time, the in-memory objects (e.g. OriginInfo) are only being
     97  // created so it doesn't make sense to tunnel quota information to QuotaVFS
     98  // to get corresponding QuotaObject instance for the SQLite file).
     99  MOZ_DIAGNOSTIC_ASSERT(directoryMetadata.mDirectoryLockId == -1);
    100 
    101 #ifdef DEBUG
    102  {
    103    QM_TRY_INSPECT(const bool& exists,
    104                   MOZ_TO_RESULT_INVOKE_MEMBER(aDBFile, Exists));
    105    MOZ_ASSERT(exists);
    106  }
    107 #endif
    108 
    109  QM_TRY_INSPECT(const auto& conn,
    110                 OpenDBConnection(directoryMetadata, aDBFile, aMaybeCipherKey));
    111 
    112  // Make sure that the database has the latest schema before we try to read
    113  // from it. We have to do this because GetTotalDiskUsageFromDB is called
    114  // by InitOrigin. And it means that SetupAction::RunSyncWithDBOnTarget hasn't
    115  // checked the schema for the given origin yet).
    116  QM_TRY(MOZ_TO_RESULT(db::CreateOrMigrateSchema(aDir, *conn)));
    117 
    118  QM_TRY_RETURN(db::GetTotalDiskUsage(*conn));
    119 }
    120 
    121 }  // namespace
    122 
    123 const nsLiteralString kCachesSQLiteFilename = u"caches.sqlite"_ns;
    124 const nsLiteralString kMorgueDirectoryFilename = u"morgue"_ns;
    125 
    126 CacheQuotaClient::CacheQuotaClient() {
    127  AssertIsOnBackgroundThread();
    128  MOZ_DIAGNOSTIC_ASSERT(!sInstance);
    129  sInstance = this;
    130 }
    131 
    132 // static
    133 CacheQuotaClient* CacheQuotaClient::Get() {
    134  MOZ_DIAGNOSTIC_ASSERT(sInstance);
    135  return sInstance;
    136 }
    137 
    138 CacheQuotaClient::Type CacheQuotaClient::GetType() { return DOMCACHE; }
    139 
    140 Result<UsageInfo, nsresult> CacheQuotaClient::InitOrigin(
    141    PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata,
    142    const AtomicBool& aCanceled) {
    143  GECKO_TRACE_SCOPE("dom::cache", "CacheQuotaClient::InitOrigin");
    144 
    145  AssertIsOnIOThread();
    146  MOZ_ASSERT(aOriginMetadata.mPersistenceType == aPersistenceType);
    147 
    148  QuotaManager* const qm = QuotaManager::Get();
    149  MOZ_DIAGNOSTIC_ASSERT(qm);
    150 
    151  QM_TRY_INSPECT(const auto& dir, qm->GetOriginDirectory(aOriginMetadata));
    152 
    153  QM_TRY(MOZ_TO_RESULT(
    154      dir->Append(NS_LITERAL_STRING_FROM_CSTRING(DOMCACHE_DIRECTORY_NAME))));
    155 
    156  QM_TRY_INSPECT(
    157      const auto& cachesSQLiteFile,
    158      ([dir]() -> Result<nsCOMPtr<nsIFile>, nsresult> {
    159        QM_TRY_INSPECT(const auto& cachesSQLite,
    160                       CloneFileAndAppend(*dir, kCachesSQLiteFilename));
    161 
    162        // IsDirectory is used to check if caches.sqlite exists or not. Another
    163        // benefit of this is that we can test the failed cases by creating a
    164        // directory named "caches.sqlite".
    165        QM_TRY_INSPECT(const auto& dirEntryKind,
    166                       GetDirEntryKind(*cachesSQLite));
    167        if (dirEntryKind == nsIFileKind::DoesNotExist) {
    168          // We only ensure padding files and morgue directory get removed like
    169          // WipeDatabase in DBAction.cpp. The -wal journal file will be
    170          // automatically deleted by sqlite when the new database is created.
    171          // XXX Ideally, we would delete the -wal journal file as well (here
    172          // and also in WipeDatabase).
    173          // XXX We should have something like WipeDatabaseNoQuota for this.
    174          // XXX Long term, we might even think about removing entire origin
    175          // directory because missing caches.sqlite while other files exist can
    176          // be interpreted as database corruption.
    177          QM_TRY(MOZ_TO_RESULT(mozilla::dom::cache::DirectoryPaddingDeleteFile(
    178              *dir, DirPaddingFile::TMP_FILE)));
    179 
    180          QM_TRY(MOZ_TO_RESULT(mozilla::dom::cache::DirectoryPaddingDeleteFile(
    181              *dir, DirPaddingFile::FILE)));
    182 
    183          QM_TRY_INSPECT(const auto& morgueDir,
    184                         CloneFileAndAppend(*dir, kMorgueDirectoryFilename));
    185 
    186          QM_TRY(MOZ_TO_RESULT(mozilla::dom::cache::RemoveNsIFileRecursively(
    187              Nothing(), *morgueDir,
    188              /* aTrackQuota */ false)));
    189 
    190          return nsCOMPtr<nsIFile>{nullptr};
    191        }
    192 
    193        QM_TRY(OkIf(dirEntryKind == nsIFileKind::ExistsAsFile),
    194               Err(NS_ERROR_FAILURE));
    195 
    196        return cachesSQLite;
    197      }()));
    198 
    199  // If the caches.sqlite doesn't exist, then padding files and morgue directory
    200  // should have been removed if they existed. We ignore the rest of known files
    201  // because we assume that they will be removed when a new database is created.
    202  // XXX Ensure the -wel file is removed if the caches.sqlite doesn't exist.
    203  QM_TRY(OkIf(!!cachesSQLiteFile), UsageInfo{});
    204 
    205  const auto maybeCipherKey = [this, &aOriginMetadata] {
    206    Maybe<CipherKey> maybeCipherKey;
    207    auto cipherKeyManager = GetOrCreateCipherKeyManager(aOriginMetadata);
    208    if (cipherKeyManager) {
    209      maybeCipherKey = Some(cipherKeyManager->Ensure());
    210    }
    211    return maybeCipherKey;
    212  }();
    213 
    214  QM_TRY_INSPECT(
    215      const auto& paddingSize,
    216      ([dir, cachesSQLiteFile, &aOriginMetadata,
    217        &maybeCipherKey]() -> Result<int64_t, nsresult> {
    218        if (!DirectoryPaddingFileExists(*dir, DirPaddingFile::TMP_FILE)) {
    219          QM_WARNONLY_TRY_UNWRAP(const auto maybePaddingSize,
    220                                 DirectoryPaddingGet(*dir));
    221          if (maybePaddingSize) {
    222            return maybePaddingSize.ref();
    223          }
    224        }
    225 
    226        // If the temporary file still exists or failing to get the padding size
    227        // from the padding file, then we need to get the padding size from the
    228        // database and restore the padding file.
    229        QM_TRY_RETURN(GetPaddingSizeFromDB(*dir, *cachesSQLiteFile,
    230                                           aOriginMetadata, maybeCipherKey));
    231      }()));
    232 
    233  QM_TRY_INSPECT(const auto& totalDiskUsage,
    234                 GetTotalDiskUsageFromDB(*dir, *cachesSQLiteFile,
    235                                         aOriginMetadata, maybeCipherKey));
    236 
    237  QM_TRY_INSPECT(
    238      const auto& innerUsageInfo,
    239      ReduceUsageInfo(
    240          *dir, aCanceled,
    241          [](const nsCOMPtr<nsIFile>& file) -> Result<UsageInfo, nsresult> {
    242            QM_TRY_INSPECT(const auto& leafName,
    243                           MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, file,
    244                                                             GetLeafName));
    245 
    246            QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*file));
    247 
    248            switch (dirEntryKind) {
    249              case nsIFileKind::ExistsAsDirectory:
    250                if (!leafName.EqualsLiteral("morgue")) {
    251                  NS_WARNING("Unknown Cache directory found!");
    252                }
    253 
    254                break;
    255 
    256              case nsIFileKind::ExistsAsFile:
    257                // Ignore transient sqlite files and marker files
    258                if (leafName.EqualsLiteral("caches.sqlite-journal") ||
    259                    leafName.EqualsLiteral("caches.sqlite-shm") ||
    260                    StringBeginsWith(leafName, u"caches.sqlite-mj"_ns) ||
    261                    leafName.EqualsLiteral("context_open.marker")) {
    262                  break;
    263                }
    264 
    265                if (leafName.Equals(kCachesSQLiteFilename) ||
    266                    leafName.EqualsLiteral("caches.sqlite-wal")) {
    267                  QM_TRY_INSPECT(
    268                      const int64_t& fileSize,
    269                      MOZ_TO_RESULT_INVOKE_MEMBER(file, GetFileSize));
    270                  MOZ_DIAGNOSTIC_ASSERT(fileSize >= 0);
    271 
    272                  return UsageInfo{DatabaseUsageType(Some(fileSize))};
    273                }
    274 
    275                // Ignore directory padding file
    276                if (leafName.EqualsLiteral(PADDING_FILE_NAME) ||
    277                    leafName.EqualsLiteral(PADDING_TMP_FILE_NAME)) {
    278                  break;
    279                }
    280 
    281                NS_WARNING("Unknown Cache file found!");
    282 
    283                break;
    284 
    285              case nsIFileKind::DoesNotExist:
    286                // Ignore files that got removed externally while iterating.
    287                break;
    288            }
    289 
    290            return UsageInfo{};
    291          }));
    292 
    293  // FIXME: Separate file usage and database usage in OriginInfo so that the
    294  // workaround for treating padding file size as database usage can be removed.
    295  return UsageInfo{DatabaseUsageType(Some(paddingSize))} +
    296         UsageInfo{DatabaseUsageType(Some(totalDiskUsage))} + innerUsageInfo;
    297 }
    298 
    299 nsresult CacheQuotaClient::InitOriginWithoutTracking(
    300    PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata,
    301    const AtomicBool& aCanceled) {
    302  AssertIsOnIOThread();
    303 
    304  // This is called when a storage/permanent/${origin}/cache directory exists.
    305  // Even though this shouldn't happen with a "good" profile, we shouldn't
    306  // return an error here, since that would cause origin initialization to fail.
    307  // We just warn and otherwise ignore that.
    308  UNKNOWN_FILE_WARNING(NS_LITERAL_STRING_FROM_CSTRING(DOMCACHE_DIRECTORY_NAME));
    309  return NS_OK;
    310 }
    311 
    312 Result<UsageInfo, nsresult> CacheQuotaClient::GetUsageForOrigin(
    313    PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata,
    314    const AtomicBool& aCanceled) {
    315  AssertIsOnIOThread();
    316 
    317  // We can't open the database at this point, since it can be already used by
    318  // the Cache IO thread. Use the cached value instead.
    319 
    320  QuotaManager* quotaManager = QuotaManager::Get();
    321  MOZ_ASSERT(quotaManager);
    322 
    323  return quotaManager->GetUsageForClient(aOriginMetadata.mPersistenceType,
    324                                         aOriginMetadata, Client::DOMCACHE);
    325 }
    326 
    327 void CacheQuotaClient::OnOriginClearCompleted(
    328    const OriginMetadata& aOriginMetadata) {
    329  AssertIsOnIOThread();
    330 
    331  if (aOriginMetadata.mPersistenceType == quota::PERSISTENCE_TYPE_PRIVATE) {
    332    if (auto entry = mCipherKeyManagers.Lookup(aOriginMetadata.mOrigin)) {
    333      entry.Data()->Invalidate();
    334      entry.Remove();
    335    }
    336  }
    337 }
    338 
    339 void CacheQuotaClient::OnRepositoryClearCompleted(
    340    PersistenceType aPersistenceType) {
    341  AssertIsOnIOThread();
    342 
    343  if (aPersistenceType == quota::PERSISTENCE_TYPE_PRIVATE) {
    344    for (const auto& cipherKeyManager : mCipherKeyManagers.Values()) {
    345      cipherKeyManager->Invalidate();
    346    }
    347 
    348    mCipherKeyManagers.Clear();
    349  }
    350 }
    351 
    352 void CacheQuotaClient::ReleaseIOThreadObjects() {
    353  // Nothing to do here as the Context handles cleaning everything up
    354  // automatically.
    355 }
    356 
    357 void CacheQuotaClient::AbortOperationsForLocks(
    358    const DirectoryLockIdTable& aDirectoryLockIds) {
    359  AssertIsOnBackgroundThread();
    360 
    361  Manager::Abort(aDirectoryLockIds);
    362 }
    363 
    364 void CacheQuotaClient::AbortOperationsForProcess(
    365    ContentParentId aContentParentId) {
    366  // The Cache and Context can be shared by multiple client processes.  They
    367  // are not exclusively owned by a single process.
    368  //
    369  // As far as I can tell this is used by QuotaManager to abort operations
    370  // when a particular process goes away.  We definitely don't want this
    371  // since we are shared.  Also, the Cache actor code already properly
    372  // handles asynchronous actor destruction when the child process dies.
    373  //
    374  // Therefore, do nothing here.
    375 }
    376 
    377 void CacheQuotaClient::AbortAllOperations() {
    378  AssertIsOnBackgroundThread();
    379 
    380  Manager::AbortAll();
    381 }
    382 
    383 void CacheQuotaClient::StartIdleMaintenance() {}
    384 
    385 void CacheQuotaClient::StopIdleMaintenance() {}
    386 
    387 void CacheQuotaClient::InitiateShutdown() {
    388  AssertIsOnBackgroundThread();
    389 
    390  Manager::InitiateShutdown();
    391 }
    392 
    393 bool CacheQuotaClient::IsShutdownCompleted() const {
    394  AssertIsOnBackgroundThread();
    395 
    396  return Manager::IsShutdownAllComplete();
    397 }
    398 
    399 void CacheQuotaClient::ForceKillActors() {
    400  // Currently we don't implement killing actors (are there any to kill here?).
    401 }
    402 
    403 nsCString CacheQuotaClient::GetShutdownStatus() const {
    404  AssertIsOnBackgroundThread();
    405 
    406  return Manager::GetShutdownStatus();
    407 }
    408 
    409 void CacheQuotaClient::FinalizeShutdown() {
    410  // Nothing to do here.
    411 }
    412 
    413 nsresult CacheQuotaClient::UpgradeStorageFrom2_0To2_1(nsIFile* aDirectory) {
    414  AssertIsOnIOThread();
    415  MOZ_DIAGNOSTIC_ASSERT(aDirectory);
    416 
    417  QM_TRY(MOZ_TO_RESULT(DirectoryPaddingInit(*aDirectory)));
    418 
    419  return NS_OK;
    420 }
    421 
    422 nsresult CacheQuotaClient::RestorePaddingFileInternal(
    423    nsIFile* aBaseDir, mozIStorageConnection* aConn) {
    424  MOZ_ASSERT(!NS_IsMainThread());
    425  MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
    426  MOZ_DIAGNOSTIC_ASSERT(aConn);
    427 
    428  QM_TRY_INSPECT(const int64_t& dummyPaddingSize,
    429                 DirectoryPaddingRestore(*aBaseDir, *aConn,
    430                                         /* aMustRestore */ true));
    431  (void)dummyPaddingSize;
    432 
    433  return NS_OK;
    434 }
    435 
    436 nsresult CacheQuotaClient::WipePaddingFileInternal(
    437    const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile* aBaseDir) {
    438  MOZ_ASSERT(!NS_IsMainThread());
    439  MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
    440 
    441  MOZ_ASSERT(DirectoryPaddingFileExists(*aBaseDir, DirPaddingFile::FILE));
    442 
    443  QM_TRY_INSPECT(
    444      const int64_t& paddingSize, ([&aBaseDir]() -> Result<int64_t, nsresult> {
    445        const bool temporaryPaddingFileExist =
    446            DirectoryPaddingFileExists(*aBaseDir, DirPaddingFile::TMP_FILE);
    447 
    448        Maybe<int64_t> directoryPaddingGetResult;
    449        if (!temporaryPaddingFileExist) {
    450          QM_TRY_UNWRAP(directoryPaddingGetResult,
    451                        ([&aBaseDir]() -> Result<Maybe<int64_t>, nsresult> {
    452                          QM_TRY_RETURN(
    453                              DirectoryPaddingGet(*aBaseDir).map(Some<int64_t>),
    454                              Maybe<int64_t>{});
    455                        }()));
    456        }
    457 
    458        if (temporaryPaddingFileExist || !directoryPaddingGetResult) {
    459          // XXXtt: Maybe have a method in the QuotaManager to clean the usage
    460          // under the quota client and the origin. There is nothing we can do
    461          // to recover the file.
    462          NS_WARNING("Cannnot read padding size from file!");
    463          return 0;
    464        }
    465 
    466        return *directoryPaddingGetResult;
    467      }()));
    468 
    469  if (paddingSize > 0) {
    470    DecreaseUsageForDirectoryMetadata(aDirectoryMetadata, paddingSize);
    471  }
    472 
    473  QM_TRY(MOZ_TO_RESULT(
    474      DirectoryPaddingDeleteFile(*aBaseDir, DirPaddingFile::FILE)));
    475 
    476  // Remove temporary file if we have one.
    477  QM_TRY(MOZ_TO_RESULT(
    478      DirectoryPaddingDeleteFile(*aBaseDir, DirPaddingFile::TMP_FILE)));
    479 
    480  QM_TRY(MOZ_TO_RESULT(DirectoryPaddingInit(*aBaseDir)));
    481 
    482  return NS_OK;
    483 }
    484 
    485 RefPtr<CipherKeyManager> CacheQuotaClient::GetOrCreateCipherKeyManager(
    486    const PrincipalMetadata& aMetadata) {
    487  AssertIsOnIOThread();
    488 
    489  auto privateOrigin = aMetadata.mIsPrivate;
    490  if (!privateOrigin) {
    491    return nullptr;
    492  }
    493 
    494  const auto& origin = aMetadata.mOrigin;
    495  return mCipherKeyManagers.LookupOrInsertWith(
    496      origin, [] { return new CipherKeyManager("CacheCipherKeyManager"); });
    497 }
    498 
    499 CacheQuotaClient::~CacheQuotaClient() {
    500  AssertIsOnBackgroundThread();
    501  MOZ_DIAGNOSTIC_ASSERT(sInstance == this);
    502 
    503  sInstance = nullptr;
    504 }
    505 
    506 // static
    507 CacheQuotaClient* CacheQuotaClient::sInstance = nullptr;
    508 
    509 // static
    510 already_AddRefed<quota::Client> CreateQuotaClient() {
    511  AssertIsOnBackgroundThread();
    512 
    513  RefPtr<CacheQuotaClient> ref = new CacheQuotaClient();
    514  return ref.forget();
    515 }
    516 
    517 // static
    518 nsresult RestorePaddingFile(nsIFile* aBaseDir, mozIStorageConnection* aConn) {
    519  MOZ_ASSERT(!NS_IsMainThread());
    520  MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
    521  MOZ_DIAGNOSTIC_ASSERT(aConn);
    522 
    523  RefPtr<CacheQuotaClient> cacheQuotaClient = CacheQuotaClient::Get();
    524  MOZ_DIAGNOSTIC_ASSERT(cacheQuotaClient);
    525 
    526  QM_TRY(MOZ_TO_RESULT(
    527      cacheQuotaClient->RestorePaddingFileInternal(aBaseDir, aConn)));
    528 
    529  return NS_OK;
    530 }
    531 
    532 // static
    533 nsresult WipePaddingFile(const CacheDirectoryMetadata& aDirectoryMetadata,
    534                         nsIFile* aBaseDir) {
    535  MOZ_ASSERT(!NS_IsMainThread());
    536  MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
    537 
    538  RefPtr<CacheQuotaClient> cacheQuotaClient = CacheQuotaClient::Get();
    539  MOZ_DIAGNOSTIC_ASSERT(cacheQuotaClient);
    540 
    541  QM_TRY(MOZ_TO_RESULT(
    542      cacheQuotaClient->WipePaddingFileInternal(aDirectoryMetadata, aBaseDir)));
    543 
    544  return NS_OK;
    545 }
    546 
    547 }  // namespace mozilla::dom::cache