diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp index a1b88f244f87..b9d27dc7de4f 100644 --- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -19,6 +19,7 @@ #include "OriginInfo.h" #include "QuotaCommon.h" #include "QuotaManager.h" +#include "QuotaUsageRequestBase.h" #include "ResolvableOriginOp.h" #include "SanitizationUtils.h" #include "ScopedLogExtraInfo.h" @@ -922,36 +923,6 @@ class Quota final : public PQuotaParent { const ContentParentId& aContentParentId) override; }; -class QuotaUsageRequestBase : public NormalOriginOperationBase, - public PQuotaUsageRequestParent { - protected: - QuotaUsageRequestBase(const char* aRunnableName) - : NormalOriginOperationBase(aRunnableName, Nullable(), - OriginScope::FromNull(), - Nullable(), - /* aExclusive */ false) {} - - mozilla::Result GetUsageForOrigin( - QuotaManager& aQuotaManager, PersistenceType aPersistenceType, - const OriginMetadata& aOriginMetadata); - - // Subclasses use this override to set the IPDL response value. - virtual void GetResponse(UsageRequestResponse& aResponse) = 0; - - private: - mozilla::Result GetUsageForOriginEntries( - QuotaManager& aQuotaManager, PersistenceType aPersistenceType, - const OriginMetadata& aOriginMetadata, nsIFile& aDirectory, - bool aInitialized); - - void SendResults() override; - - // IPDL methods. - void ActorDestroy(ActorDestroyReason aWhy) override; - - mozilla::ipc::IPCResult RecvCancel() final; -}; - // A mix-in class to simplify operations that need to process every origin in // one or more repositories. Sub-classes should call TraverseRepository in their // DoDirectoryWork and implement a ProcessOrigin method for their per-origin @@ -7676,150 +7647,6 @@ mozilla::ipc::IPCResult Quota::RecvAbortOperationsForProcess( return IPC_OK(); } -Result QuotaUsageRequestBase::GetUsageForOrigin( - QuotaManager& aQuotaManager, PersistenceType aPersistenceType, - const OriginMetadata& aOriginMetadata) { - AssertIsOnIOThread(); - MOZ_ASSERT(aOriginMetadata.mPersistenceType == aPersistenceType); - - QM_TRY_INSPECT(const auto& directory, - aQuotaManager.GetOriginDirectory(aOriginMetadata)); - - QM_TRY_INSPECT(const bool& exists, - MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists)); - - if (!exists || mCanceled) { - return UsageInfo(); - } - - // If the directory exists then enumerate all the files inside, adding up - // the sizes to get the final usage statistic. - bool initialized; - - if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) { - initialized = aQuotaManager.IsOriginInitialized(aOriginMetadata.mOrigin); - } else { - initialized = aQuotaManager.IsTemporaryStorageInitialized(); - } - - return GetUsageForOriginEntries(aQuotaManager, aPersistenceType, - aOriginMetadata, *directory, initialized); -} - -Result QuotaUsageRequestBase::GetUsageForOriginEntries( - QuotaManager& aQuotaManager, PersistenceType aPersistenceType, - const OriginMetadata& aOriginMetadata, nsIFile& aDirectory, - const bool aInitialized) { - AssertIsOnIOThread(); - - QM_TRY_RETURN((ReduceEachFileAtomicCancelable( - aDirectory, mCanceled, UsageInfo{}, - [&](UsageInfo oldUsageInfo, const nsCOMPtr& file) - -> mozilla::Result { - QM_TRY_INSPECT( - const auto& leafName, - MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, file, GetLeafName)); - - QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*file)); - - switch (dirEntryKind) { - case nsIFileKind::ExistsAsDirectory: { - Client::Type clientType; - const bool ok = - Client::TypeFromText(leafName, clientType, fallible); - if (!ok) { - // Unknown directories during getting usage for an origin (even - // for an uninitialized origin) are now allowed. Just warn if we - // find them. - UNKNOWN_FILE_WARNING(leafName); - break; - } - - Client* const client = aQuotaManager.GetClient(clientType); - MOZ_ASSERT(client); - - QM_TRY_INSPECT( - const auto& usageInfo, - aInitialized ? client->GetUsageForOrigin( - aPersistenceType, aOriginMetadata, mCanceled) - : client->InitOrigin(aPersistenceType, - aOriginMetadata, mCanceled)); - return oldUsageInfo + usageInfo; - } - - case nsIFileKind::ExistsAsFile: - // We are maintaining existing behavior for unknown files here (just - // continuing). - // This can possibly be used by developers to add temporary backups - // into origin directories without losing get usage functionality. - if (IsTempMetadata(leafName)) { - if (!aInitialized) { - QM_TRY(MOZ_TO_RESULT(file->Remove(/* recursive */ false))); - } - - break; - } - - if (IsOriginMetadata(leafName) || IsOSMetadata(leafName) || - IsDotFile(leafName)) { - break; - } - - // Unknown files during getting usage for an origin (even for an - // uninitialized origin) are now allowed. Just warn if we find them. - UNKNOWN_FILE_WARNING(leafName); - break; - - case nsIFileKind::DoesNotExist: - // Ignore files that got removed externally while iterating. - break; - } - - return oldUsageInfo; - }))); -} - -void QuotaUsageRequestBase::SendResults() { - AssertIsOnOwningThread(); - - if (IsActorDestroyed()) { - if (NS_SUCCEEDED(mResultCode)) { - mResultCode = NS_ERROR_FAILURE; - } - } else { - if (mCanceled) { - mResultCode = NS_ERROR_FAILURE; - } - - UsageRequestResponse response; - - if (NS_SUCCEEDED(mResultCode)) { - GetResponse(response); - } else { - response = mResultCode; - } - - Unused << PQuotaUsageRequestParent::Send__delete__(this, response); - } -} - -void QuotaUsageRequestBase::ActorDestroy(ActorDestroyReason aWhy) { - AssertIsOnOwningThread(); - - NoteActorDestroyed(); -} - -mozilla::ipc::IPCResult QuotaUsageRequestBase::RecvCancel() { - AssertIsOnOwningThread(); - - if (mCanceled.exchange(true)) { - NS_WARNING("Canceled more than once?!"); - return IPC_FAIL(this, "Request canceled more than once"); - } - - return IPC_OK(); -} - nsresult TraverseRepositoryHelper::TraverseRepository( QuotaManager& aQuotaManager, PersistenceType aPersistenceType) { AssertIsOnIOThread(); diff --git a/dom/quota/QuotaUsageRequestBase.cpp b/dom/quota/QuotaUsageRequestBase.cpp new file mode 100644 index 000000000000..bb1e92e4deff --- /dev/null +++ b/dom/quota/QuotaUsageRequestBase.cpp @@ -0,0 +1,165 @@ +/* -*- 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/. */ + +#include "QuotaUsageRequestBase.h" + +#include "mozilla/dom/quota/Assertions.h" +#include "mozilla/dom/quota/CommonMetadata.h" +#include "mozilla/dom/quota/FileUtils.h" +#include "mozilla/dom/quota/PQuotaRequest.h" +#include "mozilla/dom/quota/QuotaCommon.h" +#include "mozilla/dom/quota/QuotaManager.h" +#include "mozilla/dom/quota/ResultExtensions.h" +#include "mozilla/dom/quota/UsageInfo.h" +#include "nsIFile.h" + +namespace mozilla::dom::quota { + +Result QuotaUsageRequestBase::GetUsageForOrigin( + QuotaManager& aQuotaManager, PersistenceType aPersistenceType, + const OriginMetadata& aOriginMetadata) { + AssertIsOnIOThread(); + MOZ_ASSERT(aOriginMetadata.mPersistenceType == aPersistenceType); + + QM_TRY_INSPECT(const auto& directory, + aQuotaManager.GetOriginDirectory(aOriginMetadata)); + + QM_TRY_INSPECT(const bool& exists, + MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists)); + + if (!exists || mCanceled) { + return UsageInfo(); + } + + // If the directory exists then enumerate all the files inside, adding up + // the sizes to get the final usage statistic. + bool initialized; + + if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) { + initialized = aQuotaManager.IsOriginInitialized(aOriginMetadata.mOrigin); + } else { + initialized = aQuotaManager.IsTemporaryStorageInitialized(); + } + + return GetUsageForOriginEntries(aQuotaManager, aPersistenceType, + aOriginMetadata, *directory, initialized); +} + +Result QuotaUsageRequestBase::GetUsageForOriginEntries( + QuotaManager& aQuotaManager, PersistenceType aPersistenceType, + const OriginMetadata& aOriginMetadata, nsIFile& aDirectory, + const bool aInitialized) { + AssertIsOnIOThread(); + + QM_TRY_RETURN((ReduceEachFileAtomicCancelable( + aDirectory, mCanceled, UsageInfo{}, + [&](UsageInfo oldUsageInfo, const nsCOMPtr& file) + -> mozilla::Result { + QM_TRY_INSPECT( + const auto& leafName, + MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, file, GetLeafName)); + + QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*file)); + + switch (dirEntryKind) { + case nsIFileKind::ExistsAsDirectory: { + Client::Type clientType; + const bool ok = + Client::TypeFromText(leafName, clientType, fallible); + if (!ok) { + // Unknown directories during getting usage for an origin (even + // for an uninitialized origin) are now allowed. Just warn if we + // find them. + UNKNOWN_FILE_WARNING(leafName); + break; + } + + Client* const client = aQuotaManager.GetClient(clientType); + MOZ_ASSERT(client); + + QM_TRY_INSPECT( + const auto& usageInfo, + aInitialized ? client->GetUsageForOrigin( + aPersistenceType, aOriginMetadata, mCanceled) + : client->InitOrigin(aPersistenceType, + aOriginMetadata, mCanceled)); + return oldUsageInfo + usageInfo; + } + + case nsIFileKind::ExistsAsFile: + // We are maintaining existing behavior for unknown files here (just + // continuing). + // This can possibly be used by developers to add temporary backups + // into origin directories without losing get usage functionality. + if (IsTempMetadata(leafName)) { + if (!aInitialized) { + QM_TRY(MOZ_TO_RESULT(file->Remove(/* recursive */ false))); + } + + break; + } + + if (IsOriginMetadata(leafName) || IsOSMetadata(leafName) || + IsDotFile(leafName)) { + break; + } + + // Unknown files during getting usage for an origin (even for an + // uninitialized origin) are now allowed. Just warn if we find them. + UNKNOWN_FILE_WARNING(leafName); + break; + + case nsIFileKind::DoesNotExist: + // Ignore files that got removed externally while iterating. + break; + } + + return oldUsageInfo; + }))); +} + +void QuotaUsageRequestBase::SendResults() { + AssertIsOnOwningThread(); + + if (IsActorDestroyed()) { + if (NS_SUCCEEDED(mResultCode)) { + mResultCode = NS_ERROR_FAILURE; + } + } else { + if (mCanceled) { + mResultCode = NS_ERROR_FAILURE; + } + + UsageRequestResponse response; + + if (NS_SUCCEEDED(mResultCode)) { + GetResponse(response); + } else { + response = mResultCode; + } + + Unused << PQuotaUsageRequestParent::Send__delete__(this, response); + } +} + +void QuotaUsageRequestBase::ActorDestroy(ActorDestroyReason aWhy) { + AssertIsOnOwningThread(); + + NoteActorDestroyed(); +} + +mozilla::ipc::IPCResult QuotaUsageRequestBase::RecvCancel() { + AssertIsOnOwningThread(); + + if (mCanceled.exchange(true)) { + NS_WARNING("Canceled more than once?!"); + return IPC_FAIL(this, "Request canceled more than once"); + } + + return IPC_OK(); +} + +} // namespace mozilla::dom::quota diff --git a/dom/quota/QuotaUsageRequestBase.h b/dom/quota/QuotaUsageRequestBase.h new file mode 100644 index 000000000000..e88f6badc907 --- /dev/null +++ b/dom/quota/QuotaUsageRequestBase.h @@ -0,0 +1,59 @@ +/* -*- 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/. */ + +#ifndef DOM_QUOTA_QUOTAUSAGEREQUESTBASE_H_ +#define DOM_QUOTA_QUOTAUSAGEREQUESTBASE_H_ + +#include "NormalOriginOperationBase.h" +#include "mozilla/dom/quota/PQuotaUsageRequestParent.h" + +class nsIFile; + +namespace mozilla { + +template +class Result; + +namespace dom::quota { + +struct OriginMetadata; +class UsageInfo; +class UsageRequestResponse; + +class QuotaUsageRequestBase : public NormalOriginOperationBase, + public PQuotaUsageRequestParent { + protected: + QuotaUsageRequestBase(const char* aRunnableName) + : NormalOriginOperationBase(aRunnableName, Nullable(), + OriginScope::FromNull(), + Nullable(), + /* aExclusive */ false) {} + + mozilla::Result GetUsageForOrigin( + QuotaManager& aQuotaManager, PersistenceType aPersistenceType, + const OriginMetadata& aOriginMetadata); + + // Subclasses use this override to set the IPDL response value. + virtual void GetResponse(UsageRequestResponse& aResponse) = 0; + + private: + mozilla::Result GetUsageForOriginEntries( + QuotaManager& aQuotaManager, PersistenceType aPersistenceType, + const OriginMetadata& aOriginMetadata, nsIFile& aDirectory, + bool aInitialized); + + void SendResults() override; + + // IPDL methods. + void ActorDestroy(ActorDestroyReason aWhy) override; + + mozilla::ipc::IPCResult RecvCancel() final; +}; + +} // namespace dom::quota +} // namespace mozilla + +#endif // DOM_QUOTA_QUOTAUSAGEREQUESTBASE_H_ diff --git a/dom/quota/moz.build b/dom/quota/moz.build index d93bd8e90bd3..7a379bf4f41a 100644 --- a/dom/quota/moz.build +++ b/dom/quota/moz.build @@ -102,6 +102,7 @@ UNIFIED_SOURCES += [ "QuotaObject.cpp", "QuotaRequests.cpp", "QuotaResults.cpp", + "QuotaUsageRequestBase.cpp", "RemoteQuotaObject.cpp", "RemoteQuotaObjectChild.cpp", "RemoteQuotaObjectParent.cpp",