2015-03-02 16:20:00 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
#include "QuotaClientImpl.h"
|
2015-03-02 16:20:00 +03:00
|
|
|
|
2017-10-26 14:35:08 +03:00
|
|
|
#include "DBAction.h"
|
2020-04-15 02:51:44 +03:00
|
|
|
#include "FileUtilsImpl.h"
|
|
|
|
#include "mozilla/dom/cache/DBSchema.h"
|
2015-03-02 16:20:00 +03:00
|
|
|
#include "mozilla/dom/cache/Manager.h"
|
2019-01-17 20:12:27 +03:00
|
|
|
#include "mozilla/dom/quota/QuotaCommon.h"
|
2015-03-02 16:20:00 +03:00
|
|
|
#include "mozilla/dom/quota/QuotaManager.h"
|
|
|
|
#include "mozilla/dom/quota/UsageInfo.h"
|
2015-11-22 12:44:16 +03:00
|
|
|
#include "mozilla/ipc/BackgroundParent.h"
|
2019-01-17 20:12:27 +03:00
|
|
|
#include "mozilla/Telemetry.h"
|
2017-10-26 14:35:08 +03:00
|
|
|
#include "mozilla/Unused.h"
|
2015-03-02 16:20:00 +03:00
|
|
|
#include "nsIFile.h"
|
|
|
|
#include "nsThreadUtils.h"
|
|
|
|
|
2020-11-17 12:04:21 +03:00
|
|
|
namespace mozilla::dom::cache {
|
2015-03-02 16:20:00 +03:00
|
|
|
|
2017-07-18 13:54:20 +03:00
|
|
|
using mozilla::dom::quota::AssertIsOnIOThread;
|
2015-03-02 16:20:00 +03:00
|
|
|
using mozilla::dom::quota::Client;
|
2020-11-17 12:04:18 +03:00
|
|
|
using mozilla::dom::quota::CloneFileAndAppend;
|
2020-06-25 12:30:06 +03:00
|
|
|
using mozilla::dom::quota::DatabaseUsageType;
|
2020-10-20 14:46:31 +03:00
|
|
|
using mozilla::dom::quota::GroupAndOrigin;
|
2019-10-26 11:50:43 +03:00
|
|
|
using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
|
2015-03-02 16:20:00 +03:00
|
|
|
using mozilla::dom::quota::PersistenceType;
|
|
|
|
using mozilla::dom::quota::QuotaManager;
|
|
|
|
using mozilla::dom::quota::UsageInfo;
|
2015-11-22 12:44:16 +03:00
|
|
|
using mozilla::ipc::AssertIsOnBackgroundThread;
|
2015-03-02 16:20:00 +03:00
|
|
|
|
2020-11-17 12:04:21 +03:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
nsresult GetBodyUsage(nsIFile* aMorgueDir, const Atomic<bool>& aCanceled,
|
|
|
|
UsageInfo* aUsageInfo, const bool aInitializing) {
|
2017-07-18 14:03:25 +03:00
|
|
|
AssertIsOnIOThread();
|
|
|
|
|
2018-05-20 06:17:45 +03:00
|
|
|
nsCOMPtr<nsIDirectoryEnumerator> entries;
|
2019-09-27 19:54:22 +03:00
|
|
|
nsresult rv = aMorgueDir->GetDirectoryEntries(getter_AddRefs(entries));
|
2015-03-02 16:20:00 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2019-09-27 19:54:22 +03:00
|
|
|
nsCOMPtr<nsIFile> bodyDir;
|
|
|
|
while (NS_SUCCEEDED(rv = entries->GetNextFile(getter_AddRefs(bodyDir))) &&
|
|
|
|
bodyDir && !aCanceled) {
|
2019-09-13 19:43:30 +03:00
|
|
|
if (NS_WARN_IF(QuotaManager::IsShuttingDown())) {
|
|
|
|
return NS_ERROR_ABORT;
|
|
|
|
}
|
2015-03-02 16:20:00 +03:00
|
|
|
bool isDir;
|
2019-09-27 19:54:22 +03:00
|
|
|
rv = bodyDir->IsDirectory(&isDir);
|
2015-03-02 16:20:00 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2019-09-27 19:54:22 +03:00
|
|
|
if (!isDir) {
|
|
|
|
QuotaInfo dummy;
|
2020-11-17 12:04:21 +03:00
|
|
|
DebugOnly<nsresult> result =
|
2019-09-27 19:54:22 +03:00
|
|
|
RemoveNsIFile(dummy, bodyDir, /* aTrackQuota */ false);
|
|
|
|
// Try to remove the unexpected files, and keep moving on even if it fails
|
|
|
|
// because it might be created by virus or the operation system
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(result));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-09-27 19:54:45 +03:00
|
|
|
const QuotaInfo dummy;
|
|
|
|
const auto getUsage = [&aUsageInfo](nsIFile* bodyFile,
|
|
|
|
const nsACString& leafName,
|
|
|
|
bool& fileDeleted) {
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(bodyFile);
|
|
|
|
Unused << leafName;
|
2019-09-27 19:54:22 +03:00
|
|
|
|
|
|
|
int64_t fileSize;
|
2019-09-27 19:54:45 +03:00
|
|
|
nsresult rv = bodyFile->GetFileSize(&fileSize);
|
2019-09-27 19:54:22 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(fileSize >= 0);
|
2020-08-18 12:29:03 +03:00
|
|
|
// FIXME: Separate file usage and database usage in OriginInfo so that the
|
|
|
|
// workaround for treating body file size as database usage can be
|
|
|
|
// removed.
|
|
|
|
//
|
|
|
|
// This is needed because we want to remove the mutex lock for padding
|
|
|
|
// files. The lock is needed because the padding file is accessed on the
|
|
|
|
// QM IO thread while getting origin usage and is accessed on the Cache IO
|
|
|
|
// thread in normal Cache operations.
|
|
|
|
// Using the cached usage in QM while getting origin usage can remove the
|
|
|
|
// access on the QM IO thread and thus we can remove the mutex lock.
|
|
|
|
// However, QM only separates usage types in initialization, and the
|
|
|
|
// separation is gone after that. So, before extending the separation of
|
|
|
|
// usage types in QM, this is a workaround to avoid the file usage
|
|
|
|
// mismatching in our tests. Note that file usage hasn't been exposed to
|
|
|
|
// users yet.
|
|
|
|
*aUsageInfo += DatabaseUsageType(Some(fileSize));
|
2019-09-27 19:54:45 +03:00
|
|
|
|
|
|
|
fileDeleted = false;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
};
|
2020-11-17 12:04:21 +03:00
|
|
|
rv = BodyTraverseFiles(dummy, bodyDir, getUsage,
|
|
|
|
/* aCanRemoveFiles */
|
|
|
|
aInitializing,
|
|
|
|
/* aTrackQuota */ false);
|
2015-03-02 16:20:00 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
2019-09-27 19:54:22 +03:00
|
|
|
}
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
2015-03-02 16:20:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2020-11-17 12:04:21 +03:00
|
|
|
Result<int64_t, nsresult> LockedGetPaddingSizeFromDB(
|
2020-11-17 12:04:18 +03:00
|
|
|
nsIFile& aDir, const GroupAndOrigin& aGroupAndOrigin) {
|
2017-10-05 12:30:40 +03:00
|
|
|
QuotaInfo quotaInfo;
|
2020-10-20 14:46:31 +03:00
|
|
|
static_cast<GroupAndOrigin&>(quotaInfo) = aGroupAndOrigin;
|
2019-10-26 11:50:43 +03:00
|
|
|
// quotaInfo.mDirectoryLockId must be -1 (which is default for new QuotaInfo)
|
|
|
|
// because this method should only be called from QuotaClient::InitOrigin
|
|
|
|
// (via QuotaClient::GetUsageForOriginInternal) when the temporary storage
|
|
|
|
// hasn't been initialized yet. At that time, the in-memory objects (e.g.
|
|
|
|
// OriginInfo) are only being created so it doesn't make sense to tunnel
|
|
|
|
// quota information to TelemetryVFS to get corresponding QuotaObject instance
|
|
|
|
// for the SQLite file).
|
2019-10-25 15:02:10 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(quotaInfo.mDirectoryLockId == -1);
|
2019-10-26 11:50:43 +03:00
|
|
|
|
2020-11-17 12:04:18 +03:00
|
|
|
CACHE_TRY_INSPECT(const auto& dbFile,
|
|
|
|
CloneFileAndAppend(aDir, kCachesSQLiteFilename));
|
2020-06-23 09:38:25 +03:00
|
|
|
|
2020-11-17 12:04:18 +03:00
|
|
|
CACHE_TRY_INSPECT(const bool& exists, MOZ_TO_RESULT_INVOKE(dbFile, Exists));
|
2020-06-23 09:38:25 +03:00
|
|
|
|
2020-11-17 12:04:18 +03:00
|
|
|
// Return size = 0 if caches.sqlite doesn't exist.
|
2020-06-23 09:38:25 +03:00
|
|
|
// This function is only called if the value of the padding size couldn't be
|
|
|
|
// determined from the padding file, possibly because it doesn't exist, or a
|
|
|
|
// leftover temporary padding file was found.
|
|
|
|
// There is no other way to get the overall padding size of an origin.
|
|
|
|
if (!exists) {
|
2020-11-17 12:04:18 +03:00
|
|
|
return 0;
|
2017-10-05 12:30:40 +03:00
|
|
|
}
|
2020-06-23 09:38:25 +03:00
|
|
|
|
2020-11-17 12:04:21 +03:00
|
|
|
CACHE_TRY_INSPECT(const auto& conn,
|
|
|
|
ToResultInvoke<nsCOMPtr<mozIStorageConnection>>(
|
|
|
|
OpenDBConnection, quotaInfo, dbFile));
|
2017-10-05 12:30:40 +03:00
|
|
|
|
2018-09-07 11:28:30 +03:00
|
|
|
// Make sure that the database has the latest schema before we try to read
|
|
|
|
// from it. We have to do this because LockedGetPaddingSizeFromDB is called
|
|
|
|
// by QuotaClient::GetUsageForOrigin which may run at any time (there's no
|
|
|
|
// guarantee that SetupAction::RunSyncWithDBOnTarget already checked the
|
|
|
|
// schema for the given origin).
|
2020-11-17 12:04:21 +03:00
|
|
|
CACHE_TRY(db::CreateOrMigrateSchema(*conn));
|
2018-09-07 11:28:30 +03:00
|
|
|
|
2020-11-17 12:04:21 +03:00
|
|
|
CACHE_TRY_RETURN(ToResultInvoke<int64_t>(LockedDirectoryPaddingRestore, &aDir,
|
|
|
|
conn,
|
|
|
|
/* aMustRestore */ false));
|
2017-10-05 12:30:40 +03:00
|
|
|
}
|
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
} // namespace
|
2017-07-18 14:00:09 +03:00
|
|
|
|
2020-07-01 11:42:31 +03:00
|
|
|
const nsLiteralString kCachesSQLiteFilename = u"caches.sqlite"_ns;
|
2020-06-23 09:38:25 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
CacheQuotaClient::CacheQuotaClient()
|
|
|
|
: mDirPaddingFileMutex("DOMCacheQuotaClient.mDirPaddingFileMutex") {
|
|
|
|
AssertIsOnBackgroundThread();
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!sInstance);
|
|
|
|
sInstance = this;
|
|
|
|
}
|
2017-07-20 06:33:39 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
// static
|
|
|
|
CacheQuotaClient* CacheQuotaClient::Get() {
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(sInstance);
|
|
|
|
return sInstance;
|
|
|
|
}
|
2015-03-02 16:20:00 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
CacheQuotaClient::Type CacheQuotaClient::GetType() { return DOMCACHE; }
|
2017-07-18 14:03:25 +03:00
|
|
|
|
2020-06-25 12:31:39 +03:00
|
|
|
Result<UsageInfo, nsresult> CacheQuotaClient::InitOrigin(
|
2020-10-20 14:46:31 +03:00
|
|
|
PersistenceType aPersistenceType, const GroupAndOrigin& aGroupAndOrigin,
|
|
|
|
const AtomicBool& aCanceled) {
|
2020-04-15 02:51:44 +03:00
|
|
|
AssertIsOnIOThread();
|
2015-05-20 03:47:16 +03:00
|
|
|
|
2020-10-20 14:46:31 +03:00
|
|
|
return GetUsageForOriginInternal(aPersistenceType, aGroupAndOrigin, aCanceled,
|
2020-06-25 11:35:13 +03:00
|
|
|
/* aInitializing*/ true);
|
2020-06-25 12:31:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult CacheQuotaClient::InitOriginWithoutTracking(
|
2020-10-20 14:46:31 +03:00
|
|
|
PersistenceType aPersistenceType, const GroupAndOrigin& aGroupAndOrigin,
|
|
|
|
const AtomicBool& aCanceled) {
|
2020-06-25 12:31:39 +03:00
|
|
|
AssertIsOnIOThread();
|
|
|
|
|
|
|
|
// This is called when a storage/permanent/chrome/cache directory exists. Even
|
|
|
|
// though this shouldn't happen with a "good" profile, we shouldn't return an
|
|
|
|
// error here, since that would cause origin initialization to fail. We just
|
|
|
|
// warn and otherwise ignore that.
|
2020-07-01 11:34:12 +03:00
|
|
|
UNKNOWN_FILE_WARNING(NS_LITERAL_STRING_FROM_CSTRING(DOMCACHE_DIRECTORY_NAME));
|
2020-06-25 12:31:39 +03:00
|
|
|
return NS_OK;
|
2020-04-15 02:51:44 +03:00
|
|
|
}
|
2015-03-02 16:20:00 +03:00
|
|
|
|
2020-06-25 11:34:43 +03:00
|
|
|
Result<UsageInfo, nsresult> CacheQuotaClient::GetUsageForOrigin(
|
2020-10-20 14:46:31 +03:00
|
|
|
PersistenceType aPersistenceType, const GroupAndOrigin& aGroupAndOrigin,
|
|
|
|
const AtomicBool& aCanceled) {
|
2020-06-25 11:35:13 +03:00
|
|
|
AssertIsOnIOThread();
|
2020-06-25 11:34:43 +03:00
|
|
|
|
2020-10-20 14:46:31 +03:00
|
|
|
return GetUsageForOriginInternal(aPersistenceType, aGroupAndOrigin, aCanceled,
|
2020-06-25 11:35:13 +03:00
|
|
|
/* aInitializing*/ false);
|
2020-04-15 02:51:44 +03:00
|
|
|
}
|
2015-03-02 16:20:00 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
void CacheQuotaClient::OnOriginClearCompleted(PersistenceType aPersistenceType,
|
|
|
|
const nsACString& aOrigin) {
|
|
|
|
// Nothing to do here.
|
|
|
|
}
|
2015-03-02 16:20:00 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
void CacheQuotaClient::ReleaseIOThreadObjects() {
|
|
|
|
// Nothing to do here as the Context handles cleaning everything up
|
|
|
|
// automatically.
|
|
|
|
}
|
2015-03-16 17:10:36 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
void CacheQuotaClient::AbortOperations(const nsACString& aOrigin) {
|
|
|
|
AssertIsOnBackgroundThread();
|
2015-03-16 17:10:36 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
Manager::Abort(aOrigin);
|
|
|
|
}
|
2015-03-02 16:20:00 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
void CacheQuotaClient::AbortOperationsForProcess(
|
|
|
|
ContentParentId aContentParentId) {
|
|
|
|
// The Cache and Context can be shared by multiple client processes. They
|
|
|
|
// are not exclusively owned by a single process.
|
|
|
|
//
|
|
|
|
// As far as I can tell this is used by QuotaManager to abort operations
|
|
|
|
// when a particular process goes away. We definitely don't want this
|
|
|
|
// since we are shared. Also, the Cache actor code already properly
|
|
|
|
// handles asynchronous actor destruction when the child process dies.
|
|
|
|
//
|
|
|
|
// Therefore, do nothing here.
|
|
|
|
}
|
2015-11-22 12:44:16 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
void CacheQuotaClient::StartIdleMaintenance() {}
|
2015-03-02 16:20:00 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
void CacheQuotaClient::StopIdleMaintenance() {}
|
2015-03-02 16:20:00 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
void CacheQuotaClient::ShutdownWorkThreads() {
|
|
|
|
AssertIsOnBackgroundThread();
|
2015-03-02 16:20:00 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
// spins the event loop and synchronously shuts down all Managers
|
|
|
|
Manager::ShutdownAll();
|
|
|
|
}
|
2017-07-18 13:54:20 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
nsresult CacheQuotaClient::UpgradeStorageFrom2_0To2_1(nsIFile* aDirectory) {
|
|
|
|
AssertIsOnIOThread();
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aDirectory);
|
2017-07-18 14:00:09 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
MutexAutoLock lock(mDirPaddingFileMutex);
|
2017-07-18 13:54:20 +03:00
|
|
|
|
2020-11-17 12:04:21 +03:00
|
|
|
nsresult rv = LockedDirectoryPaddingInit(aDirectory);
|
2020-04-15 02:51:44 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
2017-07-18 13:57:54 +03:00
|
|
|
return rv;
|
2017-07-18 13:54:20 +03:00
|
|
|
}
|
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
return rv;
|
|
|
|
}
|
2017-07-18 14:00:09 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
nsresult CacheQuotaClient::RestorePaddingFileInternal(
|
|
|
|
nsIFile* aBaseDir, mozIStorageConnection* aConn) {
|
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aConn);
|
2017-07-18 14:00:09 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
int64_t dummyPaddingSize;
|
2017-07-18 14:00:09 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
MutexAutoLock lock(mDirPaddingFileMutex);
|
|
|
|
|
2020-11-17 12:04:21 +03:00
|
|
|
nsresult rv = LockedDirectoryPaddingRestore(
|
2020-04-15 02:51:44 +03:00
|
|
|
aBaseDir, aConn, /* aMustRestore */ true, &dummyPaddingSize);
|
|
|
|
Unused << NS_WARN_IF(NS_FAILED(rv));
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult CacheQuotaClient::WipePaddingFileInternal(const QuotaInfo& aQuotaInfo,
|
|
|
|
nsIFile* aBaseDir) {
|
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
|
|
|
|
|
|
|
|
MutexAutoLock lock(mDirPaddingFileMutex);
|
|
|
|
|
2020-11-17 12:04:21 +03:00
|
|
|
MOZ_ASSERT(DirectoryPaddingFileExists(aBaseDir, DirPaddingFile::FILE));
|
2020-04-15 02:51:44 +03:00
|
|
|
|
|
|
|
int64_t paddingSize = 0;
|
|
|
|
bool temporaryPaddingFileExist =
|
2020-11-17 12:04:21 +03:00
|
|
|
DirectoryPaddingFileExists(aBaseDir, DirPaddingFile::TMP_FILE);
|
2020-04-15 02:51:44 +03:00
|
|
|
|
|
|
|
if (temporaryPaddingFileExist ||
|
2020-11-17 12:04:21 +03:00
|
|
|
NS_WARN_IF(
|
|
|
|
NS_FAILED(LockedDirectoryPaddingGet(aBaseDir, &paddingSize)))) {
|
2020-04-15 02:51:44 +03:00
|
|
|
// XXXtt: Maybe have a method in the QuotaManager to clean the usage under
|
|
|
|
// the quota client and the origin.
|
|
|
|
// There is nothing we can do to recover the file.
|
|
|
|
NS_WARNING("Cannnot read padding size from file!");
|
|
|
|
paddingSize = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (paddingSize > 0) {
|
2020-11-17 12:04:21 +03:00
|
|
|
DecreaseUsageForQuotaInfo(aQuotaInfo, paddingSize);
|
2020-04-15 02:51:44 +03:00
|
|
|
}
|
|
|
|
|
2020-11-17 12:04:21 +03:00
|
|
|
nsresult rv =
|
|
|
|
LockedDirectoryPaddingDeleteFile(aBaseDir, DirPaddingFile::FILE);
|
2020-04-15 02:51:44 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
2017-07-18 14:00:09 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
// Remove temporary file if we have one.
|
2020-11-17 12:04:21 +03:00
|
|
|
rv = LockedDirectoryPaddingDeleteFile(aBaseDir, DirPaddingFile::TMP_FILE);
|
2020-04-15 02:51:44 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
2017-07-18 14:00:09 +03:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2020-11-17 12:04:21 +03:00
|
|
|
rv = LockedDirectoryPaddingInit(aBaseDir);
|
2020-04-15 02:51:44 +03:00
|
|
|
Unused << NS_WARN_IF(NS_FAILED(rv));
|
2017-07-18 14:00:09 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
return rv;
|
|
|
|
}
|
2017-10-05 12:30:40 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
CacheQuotaClient::~CacheQuotaClient() {
|
|
|
|
AssertIsOnBackgroundThread();
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(sInstance == this);
|
|
|
|
|
|
|
|
sInstance = nullptr;
|
|
|
|
}
|
2017-07-18 14:00:09 +03:00
|
|
|
|
2020-06-25 11:35:13 +03:00
|
|
|
Result<UsageInfo, nsresult> CacheQuotaClient::GetUsageForOriginInternal(
|
2020-10-20 14:46:31 +03:00
|
|
|
PersistenceType aPersistenceType, const GroupAndOrigin& aGroupAndOrigin,
|
|
|
|
const AtomicBool& aCanceled, const bool aInitializing) {
|
2020-04-15 02:51:44 +03:00
|
|
|
AssertIsOnIOThread();
|
2017-07-18 14:00:09 +03:00
|
|
|
|
2020-11-17 12:04:16 +03:00
|
|
|
QuotaManager* const qm = QuotaManager::Get();
|
2020-04-15 02:51:44 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(qm);
|
|
|
|
|
2020-11-17 12:04:16 +03:00
|
|
|
CACHE_TRY_INSPECT(
|
|
|
|
const auto& dir,
|
|
|
|
qm->GetDirectoryForOrigin(aPersistenceType, aGroupAndOrigin.mOrigin));
|
|
|
|
|
|
|
|
CACHE_TRY(
|
|
|
|
dir->Append(NS_LITERAL_STRING_FROM_CSTRING(DOMCACHE_DIRECTORY_NAME)));
|
|
|
|
|
|
|
|
CACHE_TRY_INSPECT(
|
|
|
|
const auto& maybePaddingSize,
|
|
|
|
([this, &dir, aInitializing,
|
|
|
|
&aGroupAndOrigin]() -> Result<Maybe<int64_t>, nsresult> {
|
|
|
|
// If the temporary file still exists after locking, it means the
|
|
|
|
// previous action failed, so restore the padding file.
|
|
|
|
MutexAutoLock lock(mDirPaddingFileMutex);
|
|
|
|
|
2020-11-17 12:04:21 +03:00
|
|
|
if (!DirectoryPaddingFileExists(dir, DirPaddingFile::TMP_FILE)) {
|
2020-11-17 12:04:16 +03:00
|
|
|
const auto& maybePaddingSize = [&dir]() -> Maybe<int64_t> {
|
|
|
|
CACHE_TRY_RETURN(
|
2020-11-17 12:04:21 +03:00
|
|
|
ToResultInvoke<int64_t>(LockedDirectoryPaddingGet, dir)
|
2020-11-17 12:04:16 +03:00
|
|
|
.map(Some<int64_t>),
|
|
|
|
Nothing{});
|
|
|
|
}();
|
|
|
|
|
|
|
|
if (maybePaddingSize) {
|
|
|
|
return maybePaddingSize;
|
|
|
|
}
|
|
|
|
}
|
2017-07-18 14:00:09 +03:00
|
|
|
|
2020-11-17 12:04:16 +03:00
|
|
|
if (aInitializing) {
|
2020-11-17 12:04:18 +03:00
|
|
|
CACHE_TRY_RETURN(LockedGetPaddingSizeFromDB(*dir, aGroupAndOrigin)
|
2020-11-17 12:04:16 +03:00
|
|
|
.map(Some<int64_t>));
|
2020-04-15 02:51:44 +03:00
|
|
|
}
|
2020-11-17 12:04:16 +03:00
|
|
|
|
2020-04-15 02:51:44 +03:00
|
|
|
// We can't open the database at this point, since it can be already
|
2020-11-17 12:04:16 +03:00
|
|
|
// used by Cache IO thread. Use the cached value instead. (In
|
|
|
|
// theory, we could check if the database is actually used by Cache
|
|
|
|
// IO thread at this moment, but it's probably not worth additional
|
|
|
|
// complexity.)
|
2017-07-18 14:00:09 +03:00
|
|
|
|
2020-11-17 12:04:16 +03:00
|
|
|
return Maybe<int64_t>{};
|
|
|
|
}()));
|
2017-10-05 12:30:40 +03:00
|
|
|
|
2020-06-25 11:35:13 +03:00
|
|
|
UsageInfo usageInfo;
|
|
|
|
|
2020-11-17 12:04:16 +03:00
|
|
|
if (!maybePaddingSize) {
|
2020-04-15 02:51:44 +03:00
|
|
|
uint64_t usage;
|
2020-10-20 14:46:31 +03:00
|
|
|
if (qm->GetUsageForClient(PERSISTENCE_TYPE_DEFAULT, aGroupAndOrigin,
|
2020-04-15 02:51:44 +03:00
|
|
|
Client::DOMCACHE, usage)) {
|
2020-06-25 12:30:06 +03:00
|
|
|
usageInfo += DatabaseUsageType(Some(usage));
|
2017-07-18 14:00:09 +03:00
|
|
|
}
|
|
|
|
|
2020-06-25 11:35:13 +03:00
|
|
|
return usageInfo;
|
2017-07-18 14:00:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-18 12:29:03 +03:00
|
|
|
// FIXME: Separate file usage and database usage in OriginInfo so that the
|
|
|
|
// workaround for treating padding file size as database usage can be removed.
|
2020-11-17 12:04:16 +03:00
|
|
|
usageInfo += DatabaseUsageType(maybePaddingSize);
|
|
|
|
|
|
|
|
// XXX The following loop (including the cancellation check) is very similar
|
|
|
|
// to QuotaClient::GetDatabaseFilenames in dom/indexedDB/ActorsParent.cpp
|
|
|
|
CACHE_TRY_INSPECT(const auto& entries,
|
|
|
|
MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<nsIDirectoryEnumerator>,
|
|
|
|
dir, GetDirectoryEntries));
|
|
|
|
|
|
|
|
CACHE_TRY(CollectEach(
|
|
|
|
[&entries, &aCanceled]() -> Result<nsCOMPtr<nsIFile>, nsresult> {
|
|
|
|
if (aCanceled) {
|
|
|
|
return nsCOMPtr<nsIFile>{};
|
|
|
|
}
|
2019-01-17 20:12:27 +03:00
|
|
|
|
2020-11-17 12:04:16 +03:00
|
|
|
CACHE_TRY_RETURN(MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<nsIFile>, entries,
|
|
|
|
GetNextFile));
|
|
|
|
},
|
|
|
|
[&aCanceled, &usageInfo,
|
|
|
|
aInitializing](const nsCOMPtr<nsIFile>& file) -> Result<Ok, nsresult> {
|
|
|
|
CACHE_TRY(OkIf(!QuotaManager::IsShuttingDown()), Err(NS_ERROR_ABORT));
|
|
|
|
|
|
|
|
CACHE_TRY_INSPECT(
|
|
|
|
const auto& leafName,
|
|
|
|
MOZ_TO_RESULT_INVOKE_TYPED(nsAutoString, file, GetLeafName));
|
|
|
|
|
|
|
|
CACHE_TRY_INSPECT(const bool& isDir,
|
|
|
|
MOZ_TO_RESULT_INVOKE(file, IsDirectory));
|
|
|
|
|
|
|
|
if (isDir) {
|
|
|
|
if (leafName.EqualsLiteral("morgue")) {
|
|
|
|
// XXX This didn't use to warn for NS_ERROR_ABORT, should we keep
|
|
|
|
// that? (but it was and is propagated)
|
|
|
|
CACHE_TRY(GetBodyUsage(file, aCanceled, &usageInfo, aInitializing));
|
|
|
|
} else {
|
|
|
|
NS_WARNING("Unknown Cache directory found!");
|
2019-10-25 15:02:10 +03:00
|
|
|
}
|
2020-11-17 12:04:16 +03:00
|
|
|
|
|
|
|
return Ok{};
|
2019-01-17 20:12:27 +03:00
|
|
|
}
|
2019-10-26 11:50:43 +03:00
|
|
|
|
2020-11-17 12:04:16 +03:00
|
|
|
// Ignore transient sqlite files and marker files
|
|
|
|
if (leafName.EqualsLiteral("caches.sqlite-journal") ||
|
|
|
|
leafName.EqualsLiteral("caches.sqlite-shm") ||
|
|
|
|
leafName.Find("caches.sqlite-mj"_ns, false, 0, 0) == 0 ||
|
|
|
|
leafName.EqualsLiteral("context_open.marker")) {
|
|
|
|
return Ok{};
|
|
|
|
}
|
2019-10-26 11:50:43 +03:00
|
|
|
|
2020-11-17 12:04:16 +03:00
|
|
|
if (leafName.Equals(kCachesSQLiteFilename) ||
|
|
|
|
leafName.EqualsLiteral("caches.sqlite-wal")) {
|
|
|
|
CACHE_TRY_INSPECT(const int64_t& fileSize,
|
|
|
|
MOZ_TO_RESULT_INVOKE(file, GetFileSize));
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(fileSize >= 0);
|
2019-01-17 20:12:27 +03:00
|
|
|
|
2020-11-17 12:04:16 +03:00
|
|
|
usageInfo += DatabaseUsageType(Some(fileSize));
|
|
|
|
return Ok{};
|
|
|
|
}
|
2019-01-17 20:12:27 +03:00
|
|
|
|
2020-11-17 12:04:16 +03:00
|
|
|
// Ignore directory padding file
|
|
|
|
if (leafName.EqualsLiteral(PADDING_FILE_NAME) ||
|
|
|
|
leafName.EqualsLiteral(PADDING_TMP_FILE_NAME)) {
|
|
|
|
return Ok{};
|
|
|
|
}
|
2020-04-15 02:51:44 +03:00
|
|
|
|
2020-11-17 12:04:16 +03:00
|
|
|
NS_WARNING("Unknown Cache file found!");
|
2019-01-17 20:12:27 +03:00
|
|
|
|
2020-11-17 12:04:16 +03:00
|
|
|
return Ok{};
|
|
|
|
}));
|
2019-01-17 20:12:27 +03:00
|
|
|
|
2020-06-25 11:35:13 +03:00
|
|
|
return usageInfo;
|
2020-04-15 02:51:44 +03:00
|
|
|
}
|
2015-03-02 16:20:00 +03:00
|
|
|
|
2017-07-18 14:00:09 +03:00
|
|
|
// static
|
|
|
|
CacheQuotaClient* CacheQuotaClient::sInstance = nullptr;
|
|
|
|
|
2017-07-18 13:57:54 +03:00
|
|
|
// static
|
2015-03-02 16:20:00 +03:00
|
|
|
already_AddRefed<quota::Client> CreateQuotaClient() {
|
2015-11-22 12:44:16 +03:00
|
|
|
AssertIsOnBackgroundThread();
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<CacheQuotaClient> ref = new CacheQuotaClient();
|
2015-03-02 16:20:00 +03:00
|
|
|
return ref.forget();
|
|
|
|
}
|
|
|
|
|
2017-07-18 13:57:54 +03:00
|
|
|
// static
|
|
|
|
nsresult RestorePaddingFile(nsIFile* aBaseDir, mozIStorageConnection* aConn) {
|
2017-07-18 14:03:25 +03:00
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
2017-07-18 13:57:54 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aConn);
|
|
|
|
|
2017-07-18 14:00:09 +03:00
|
|
|
RefPtr<CacheQuotaClient> cacheQuotaClient = CacheQuotaClient::Get();
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(cacheQuotaClient);
|
2017-07-18 13:57:54 +03:00
|
|
|
|
2017-07-18 14:00:09 +03:00
|
|
|
nsresult rv = cacheQuotaClient->RestorePaddingFileInternal(aBaseDir, aConn);
|
2017-07-18 13:57:54 +03:00
|
|
|
Unused << NS_WARN_IF(NS_FAILED(rv));
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
nsresult WipePaddingFile(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir) {
|
2017-07-18 14:03:25 +03:00
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
2017-07-18 13:57:54 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
|
|
|
|
|
2017-07-18 14:00:09 +03:00
|
|
|
RefPtr<CacheQuotaClient> cacheQuotaClient = CacheQuotaClient::Get();
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(cacheQuotaClient);
|
2017-07-18 13:57:54 +03:00
|
|
|
|
2017-07-18 14:00:09 +03:00
|
|
|
nsresult rv = cacheQuotaClient->WipePaddingFileInternal(aQuotaInfo, aBaseDir);
|
|
|
|
Unused << NS_WARN_IF(NS_FAILED(rv));
|
2017-07-18 13:57:54 +03:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
2020-11-17 12:04:21 +03:00
|
|
|
|
2020-11-04 20:04:01 +03:00
|
|
|
} // namespace mozilla::dom::cache
|