summaryrefslogtreecommitdiffstats
path: root/dom/quota/OriginOperations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/quota/OriginOperations.cpp')
-rw-r--r--dom/quota/OriginOperations.cpp2684
1 files changed, 2684 insertions, 0 deletions
diff --git a/dom/quota/OriginOperations.cpp b/dom/quota/OriginOperations.cpp
new file mode 100644
index 0000000000..8eb6626780
--- /dev/null
+++ b/dom/quota/OriginOperations.cpp
@@ -0,0 +1,2684 @@
+/* -*- 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 "OriginOperations.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <utility>
+
+#include "ErrorList.h"
+#include "FileUtils.h"
+#include "GroupInfo.h"
+#include "MainThreadUtils.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/NotNull.h"
+#include "mozilla/ProfilerLabels.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/Result.h"
+#include "mozilla/ResultExtensions.h"
+#include "mozilla/dom/Nullable.h"
+#include "mozilla/dom/quota/CommonMetadata.h"
+#include "mozilla/dom/quota/Client.h"
+#include "mozilla/dom/quota/Constants.h"
+#include "mozilla/dom/quota/DirectoryLock.h"
+#include "mozilla/dom/quota/PersistenceType.h"
+#include "mozilla/dom/quota/PQuota.h"
+#include "mozilla/dom/quota/PQuotaRequest.h"
+#include "mozilla/dom/quota/PQuotaUsageRequest.h"
+#include "mozilla/dom/quota/OriginScope.h"
+#include "mozilla/dom/quota/QuotaCommon.h"
+#include "mozilla/dom/quota/QuotaManager.h"
+#include "mozilla/dom/quota/QuotaManagerImpl.h"
+#include "mozilla/dom/quota/ResultExtensions.h"
+#include "mozilla/dom/quota/StreamUtils.h"
+#include "mozilla/dom/quota/UsageInfo.h"
+#include "mozilla/fallible.h"
+#include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/ipc/PBackgroundSharedTypes.h"
+#include "NormalOriginOperationBase.h"
+#include "nsCOMPtr.h"
+#include "nsTHashMap.h"
+#include "nsDebug.h"
+#include "nsError.h"
+#include "nsHashKeys.h"
+#include "nsIBinaryOutputStream.h"
+#include "nsIFile.h"
+#include "nsIObjectOutputStream.h"
+#include "nsIOutputStream.h"
+#include "nsLiteralString.h"
+#include "nsPrintfCString.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "OriginInfo.h"
+#include "OriginOperationBase.h"
+#include "QuotaRequestBase.h"
+#include "QuotaUsageRequestBase.h"
+#include "ResolvableNormalOriginOp.h"
+#include "prthread.h"
+#include "prtime.h"
+
+namespace mozilla::dom::quota {
+
+using namespace mozilla::ipc;
+
+template <class Base>
+class OpenStorageDirectoryHelper : public Base {
+ protected:
+ OpenStorageDirectoryHelper(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const char* aName)
+ : Base(std::move(aQuotaManager), aName) {}
+
+ RefPtr<BoolPromise> OpenStorageDirectory(
+ const Nullable<PersistenceType>& aPersistenceType,
+ const OriginScope& aOriginScope,
+ const Nullable<Client::Type>& aClientType, bool aExclusive);
+
+ RefPtr<UniversalDirectoryLock> mDirectoryLock;
+};
+
+class FinalizeOriginEvictionOp : public OriginOperationBase {
+ nsTArray<RefPtr<OriginDirectoryLock>> mLocks;
+
+ public:
+ FinalizeOriginEvictionOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ nsTArray<RefPtr<OriginDirectoryLock>>&& aLocks)
+ : OriginOperationBase(std::move(aQuotaManager),
+ "dom::quota::FinalizeOriginEvictionOp"),
+ mLocks(std::move(aLocks)) {
+ AssertIsOnOwningThread();
+ }
+
+ private:
+ ~FinalizeOriginEvictionOp() = default;
+
+ virtual RefPtr<BoolPromise> Open() override;
+
+ virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ virtual void UnblockOpen() override;
+};
+
+class SaveOriginAccessTimeOp
+ : public OpenStorageDirectoryHelper<NormalOriginOperationBase> {
+ const OriginMetadata mOriginMetadata;
+ int64_t mTimestamp;
+
+ public:
+ SaveOriginAccessTimeOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const OriginMetadata& aOriginMetadata,
+ int64_t aTimestamp)
+ : OpenStorageDirectoryHelper(std::move(aQuotaManager),
+ "dom::quota::SaveOriginAccessTimeOp"),
+ mOriginMetadata(aOriginMetadata),
+ mTimestamp(aTimestamp) {
+ AssertIsOnOwningThread();
+ }
+
+ private:
+ ~SaveOriginAccessTimeOp() = default;
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ virtual void SendResults() override;
+
+ void CloseDirectory() override;
+};
+
+class ClearPrivateRepositoryOp
+ : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<bool>> {
+ public:
+ explicit ClearPrivateRepositoryOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
+ : OpenStorageDirectoryHelper(std::move(aQuotaManager),
+ "dom::quota::ClearPrivateRepositoryOp") {
+ AssertIsOnOwningThread();
+ }
+
+ private:
+ ~ClearPrivateRepositoryOp() = default;
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ bool GetResolveValue() override { return true; }
+
+ void CloseDirectory() override;
+};
+
+class ShutdownStorageOp : public ResolvableNormalOriginOp<bool> {
+ RefPtr<UniversalDirectoryLock> mDirectoryLock;
+
+ public:
+ explicit ShutdownStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
+ : ResolvableNormalOriginOp(std::move(aQuotaManager),
+ "dom::quota::ShutdownStorageOp") {
+ AssertIsOnOwningThread();
+ }
+
+ private:
+ ~ShutdownStorageOp() = default;
+
+#ifdef DEBUG
+ nsresult DirectoryOpen() override;
+#endif
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ bool GetResolveValue() override { return true; }
+
+ void CloseDirectory() override;
+};
+
+// 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
+// logic.
+class TraverseRepositoryHelper {
+ public:
+ TraverseRepositoryHelper() = default;
+
+ protected:
+ virtual ~TraverseRepositoryHelper() = default;
+
+ // If ProcessOrigin returns an error, TraverseRepository will immediately
+ // terminate and return the received error code to its caller.
+ nsresult TraverseRepository(QuotaManager& aQuotaManager,
+ PersistenceType aPersistenceType);
+
+ private:
+ virtual const Atomic<bool>& GetIsCanceledFlag() = 0;
+
+ virtual nsresult ProcessOrigin(QuotaManager& aQuotaManager,
+ nsIFile& aOriginDir, const bool aPersistent,
+ const PersistenceType aPersistenceType) = 0;
+};
+
+class GetUsageOp final
+ : public OpenStorageDirectoryHelper<QuotaUsageRequestBase>,
+ public TraverseRepositoryHelper {
+ nsTArray<OriginUsage> mOriginUsages;
+ nsTHashMap<nsCStringHashKey, uint32_t> mOriginUsagesIndex;
+
+ bool mGetAll;
+
+ public:
+ GetUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const UsageRequestParams& aParams);
+
+ private:
+ ~GetUsageOp() = default;
+
+ void ProcessOriginInternal(QuotaManager* aQuotaManager,
+ const PersistenceType aPersistenceType,
+ const nsACString& aOrigin,
+ const int64_t aTimestamp, const bool aPersisted,
+ const uint64_t aUsage);
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ const Atomic<bool>& GetIsCanceledFlag() override;
+
+ nsresult ProcessOrigin(QuotaManager& aQuotaManager, nsIFile& aOriginDir,
+ const bool aPersistent,
+ const PersistenceType aPersistenceType) override;
+
+ void GetResponse(UsageRequestResponse& aResponse) override;
+
+ void CloseDirectory() override;
+};
+
+class GetOriginUsageOp final
+ : public OpenStorageDirectoryHelper<QuotaUsageRequestBase> {
+ const OriginUsageParams mParams;
+ PrincipalMetadata mPrincipalMetadata;
+ UsageInfo mUsageInfo;
+ bool mFromMemory;
+
+ public:
+ GetOriginUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const UsageRequestParams& aParams);
+
+ private:
+ ~GetOriginUsageOp() = default;
+
+ nsresult DoInit(QuotaManager& aQuotaManager) override;
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ void GetResponse(UsageRequestResponse& aResponse) override;
+
+ void CloseDirectory() override;
+};
+
+class StorageNameOp final : public QuotaRequestBase {
+ nsString mName;
+
+ public:
+ explicit StorageNameOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
+
+ private:
+ ~StorageNameOp() = default;
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ void GetResponse(RequestResponse& aResponse) override;
+
+ void CloseDirectory() override;
+};
+
+class InitializedRequestBase : public ResolvableNormalOriginOp<bool> {
+ protected:
+ bool mInitialized;
+
+ InitializedRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const char* aName);
+
+ private:
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ void CloseDirectory() override;
+};
+
+class StorageInitializedOp final : public InitializedRequestBase {
+ public:
+ explicit StorageInitializedOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
+ : InitializedRequestBase(std::move(aQuotaManager),
+ "dom::quota::StorageInitializedOp") {}
+
+ private:
+ ~StorageInitializedOp() = default;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ bool GetResolveValue() override;
+};
+
+class TemporaryStorageInitializedOp final : public InitializedRequestBase {
+ public:
+ explicit TemporaryStorageInitializedOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
+ : InitializedRequestBase(std::move(aQuotaManager),
+ "dom::quota::StorageInitializedOp") {}
+
+ private:
+ ~TemporaryStorageInitializedOp() = default;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ bool GetResolveValue() override;
+};
+
+class InitOp final : public ResolvableNormalOriginOp<bool> {
+ RefPtr<UniversalDirectoryLock> mDirectoryLock;
+
+ public:
+ InitOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ RefPtr<UniversalDirectoryLock> aDirectoryLock);
+
+ private:
+ ~InitOp() = default;
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ bool GetResolveValue() override;
+
+ void CloseDirectory() override;
+};
+
+class InitTemporaryStorageOp final : public ResolvableNormalOriginOp<bool> {
+ RefPtr<UniversalDirectoryLock> mDirectoryLock;
+
+ public:
+ InitTemporaryStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ RefPtr<UniversalDirectoryLock> aDirectoryLock);
+
+ private:
+ ~InitTemporaryStorageOp() = default;
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ bool GetResolveValue() override;
+
+ void CloseDirectory() override;
+};
+
+class InitializeOriginRequestBase : public QuotaRequestBase {
+ protected:
+ const PrincipalInfo mPrincipalInfo;
+ PrincipalMetadata mPrincipalMetadata;
+ RefPtr<UniversalDirectoryLock> mDirectoryLock;
+ const PersistenceType mPersistenceType;
+ bool mCreated;
+
+ InitializeOriginRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const char* aName,
+ PersistenceType aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo);
+
+ nsresult DoInit(QuotaManager& aQuotaManager) override;
+
+ private:
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ void CloseDirectory() override;
+};
+
+class InitializePersistentOriginOp final : public InitializeOriginRequestBase {
+ public:
+ InitializePersistentOriginOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams);
+
+ private:
+ ~InitializePersistentOriginOp() = default;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ void GetResponse(RequestResponse& aResponse) override;
+};
+
+class InitializeTemporaryOriginOp final : public InitializeOriginRequestBase {
+ public:
+ InitializeTemporaryOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams);
+
+ private:
+ ~InitializeTemporaryOriginOp() = default;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ void GetResponse(RequestResponse& aResponse) override;
+};
+
+class InitializeClientBase : public ResolvableNormalOriginOp<bool> {
+ protected:
+ const PrincipalInfo mPrincipalInfo;
+ ClientMetadata mClientMetadata;
+ RefPtr<UniversalDirectoryLock> mDirectoryLock;
+ const PersistenceType mPersistenceType;
+ const Client::Type mClientType;
+ bool mCreated;
+
+ InitializeClientBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const char* aName, PersistenceType aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo,
+ Client::Type aClientType);
+
+ nsresult DoInit(QuotaManager& aQuotaManager) override;
+
+ private:
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ void CloseDirectory() override;
+};
+
+class InitializePersistentClientOp : public InitializeClientBase {
+ public:
+ InitializePersistentClientOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const PrincipalInfo& aPrincipalInfo, Client::Type aClientType);
+
+ private:
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ bool GetResolveValue() override;
+};
+
+class InitializeTemporaryClientOp : public InitializeClientBase {
+ public:
+ InitializeTemporaryClientOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ PersistenceType aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo,
+ Client::Type aClientType);
+
+ private:
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ bool GetResolveValue() override;
+};
+
+class GetFullOriginMetadataOp
+ : public OpenStorageDirectoryHelper<QuotaRequestBase> {
+ const GetFullOriginMetadataParams mParams;
+ // XXX Consider wrapping with LazyInitializedOnce
+ OriginMetadata mOriginMetadata;
+ Maybe<FullOriginMetadata> mMaybeFullOriginMetadata;
+
+ public:
+ GetFullOriginMetadataOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const GetFullOriginMetadataParams& aParams);
+
+ private:
+ nsresult DoInit(QuotaManager& aQuotaManager) override;
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ void GetResponse(RequestResponse& aResponse) override;
+
+ void CloseDirectory() override;
+};
+
+class ClearStorageOp final
+ : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<bool>> {
+ public:
+ explicit ClearStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
+
+ private:
+ ~ClearStorageOp() = default;
+
+ void DeleteFiles(QuotaManager& aQuotaManager);
+
+ void DeleteStorageFile(QuotaManager& aQuotaManager);
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ bool GetResolveValue() override;
+
+ void CloseDirectory() override;
+};
+
+class ClearRequestBase
+ : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<bool>> {
+ protected:
+ ClearRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const char* aName)
+ : OpenStorageDirectoryHelper(std::move(aQuotaManager), aName) {
+ AssertIsOnOwningThread();
+ }
+
+ void DeleteFiles(QuotaManager& aQuotaManager,
+ const OriginMetadata& aOriginMetadata,
+ const Nullable<Client::Type>& aClientType);
+
+ void DeleteFiles(QuotaManager& aQuotaManager,
+ PersistenceType aPersistenceType,
+ const OriginScope& aOriginScope,
+ const Nullable<Client::Type>& aClientType);
+
+ private:
+ template <typename FileCollector>
+ void DeleteFilesInternal(QuotaManager& aQuotaManager,
+ PersistenceType aPersistenceType,
+ const OriginScope& aOriginScope,
+ const Nullable<Client::Type>& aClientType,
+ const FileCollector& aFileCollector);
+};
+
+class ClearOriginOp final : public ClearRequestBase {
+ const PrincipalInfo mPrincipalInfo;
+ PrincipalMetadata mPrincipalMetadata;
+ const Nullable<PersistenceType> mPersistenceType;
+ const Nullable<Client::Type> mClientType;
+
+ public:
+ ClearOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const mozilla::Maybe<PersistenceType>& aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo,
+ const mozilla::Maybe<Client::Type>& aClientType);
+
+ private:
+ ~ClearOriginOp() = default;
+
+ nsresult DoInit(QuotaManager& aQuotaManager) override;
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ bool GetResolveValue() override;
+
+ void CloseDirectory() override;
+};
+
+class ClearStoragesForOriginPrefixOp final
+ : public OpenStorageDirectoryHelper<ClearRequestBase> {
+ const nsCString mPrefix;
+ const Nullable<PersistenceType> mPersistenceType;
+
+ public:
+ ClearStoragesForOriginPrefixOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const Maybe<PersistenceType>& aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo);
+
+ private:
+ ~ClearStoragesForOriginPrefixOp() = default;
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ bool GetResolveValue() override;
+
+ void CloseDirectory() override;
+};
+
+class ClearDataOp final : public ClearRequestBase {
+ const OriginAttributesPattern mPattern;
+
+ public:
+ ClearDataOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const OriginAttributesPattern& aPattern);
+
+ private:
+ ~ClearDataOp() = default;
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ bool GetResolveValue() override;
+
+ void CloseDirectory() override;
+};
+
+class ResetOriginOp final : public QuotaRequestBase {
+ nsCString mOrigin;
+ RefPtr<UniversalDirectoryLock> mDirectoryLock;
+ Nullable<PersistenceType> mPersistenceType;
+ Nullable<Client::Type> mClientType;
+
+ public:
+ ResetOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams);
+
+ private:
+ ~ResetOriginOp() = default;
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ void GetResponse(RequestResponse& aResponse) override;
+
+ void CloseDirectory() override;
+};
+
+class PersistRequestBase : public OpenStorageDirectoryHelper<QuotaRequestBase> {
+ const PrincipalInfo mPrincipalInfo;
+
+ protected:
+ PrincipalMetadata mPrincipalMetadata;
+
+ protected:
+ PersistRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const PrincipalInfo& aPrincipalInfo);
+
+ nsresult DoInit(QuotaManager& aQuotaManager) override;
+
+ private:
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ void CloseDirectory() override;
+};
+
+class PersistedOp final : public PersistRequestBase {
+ bool mPersisted;
+
+ public:
+ PersistedOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams);
+
+ private:
+ ~PersistedOp() = default;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ void GetResponse(RequestResponse& aResponse) override;
+};
+
+class PersistOp final : public PersistRequestBase {
+ public:
+ PersistOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams);
+
+ private:
+ ~PersistOp() = default;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ void GetResponse(RequestResponse& aResponse) override;
+};
+
+class EstimateOp final : public OpenStorageDirectoryHelper<QuotaRequestBase> {
+ const EstimateParams mParams;
+ OriginMetadata mOriginMetadata;
+ std::pair<uint64_t, uint64_t> mUsageAndLimit;
+
+ public:
+ EstimateOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const EstimateParams& aParams);
+
+ private:
+ ~EstimateOp() = default;
+
+ nsresult DoInit(QuotaManager& aQuotaManager) override;
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ void GetResponse(RequestResponse& aResponse) override;
+
+ void CloseDirectory() override;
+};
+
+class ListOriginsOp final : public OpenStorageDirectoryHelper<QuotaRequestBase>,
+ public TraverseRepositoryHelper {
+ // XXX Bug 1521541 will make each origin has it's own state.
+ nsTArray<nsCString> mOrigins;
+
+ public:
+ explicit ListOriginsOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
+
+ private:
+ ~ListOriginsOp() = default;
+
+ RefPtr<BoolPromise> OpenDirectory() override;
+
+ nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
+
+ const Atomic<bool>& GetIsCanceledFlag() override;
+
+ nsresult ProcessOrigin(QuotaManager& aQuotaManager, nsIFile& aOriginDir,
+ const bool aPersistent,
+ const PersistenceType aPersistenceType) override;
+
+ void GetResponse(RequestResponse& aResponse) override;
+
+ void CloseDirectory() override;
+};
+
+RefPtr<OriginOperationBase> CreateFinalizeOriginEvictionOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ nsTArray<RefPtr<OriginDirectoryLock>>&& aLocks) {
+ return MakeRefPtr<FinalizeOriginEvictionOp>(std::move(aQuotaManager),
+ std::move(aLocks));
+}
+
+RefPtr<NormalOriginOperationBase> CreateSaveOriginAccessTimeOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const OriginMetadata& aOriginMetadata, int64_t aTimestamp) {
+ return MakeRefPtr<SaveOriginAccessTimeOp>(std::move(aQuotaManager),
+ aOriginMetadata, aTimestamp);
+}
+
+RefPtr<ResolvableNormalOriginOp<bool>> CreateClearPrivateRepositoryOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
+ return MakeRefPtr<ClearPrivateRepositoryOp>(std::move(aQuotaManager));
+}
+
+RefPtr<ResolvableNormalOriginOp<bool>> CreateShutdownStorageOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
+ return MakeRefPtr<ShutdownStorageOp>(std::move(aQuotaManager));
+}
+
+RefPtr<QuotaUsageRequestBase> CreateGetUsageOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const UsageRequestParams& aParams) {
+ return MakeRefPtr<GetUsageOp>(std::move(aQuotaManager), aParams);
+}
+
+RefPtr<QuotaUsageRequestBase> CreateGetOriginUsageOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const UsageRequestParams& aParams) {
+ return MakeRefPtr<GetOriginUsageOp>(std::move(aQuotaManager), aParams);
+}
+
+RefPtr<QuotaRequestBase> CreateStorageNameOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
+ return MakeRefPtr<StorageNameOp>(std::move(aQuotaManager));
+}
+
+RefPtr<ResolvableNormalOriginOp<bool>> CreateStorageInitializedOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
+ return MakeRefPtr<StorageInitializedOp>(std::move(aQuotaManager));
+}
+
+RefPtr<ResolvableNormalOriginOp<bool>> CreateTemporaryStorageInitializedOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
+ return MakeRefPtr<TemporaryStorageInitializedOp>(std::move(aQuotaManager));
+}
+
+RefPtr<ResolvableNormalOriginOp<bool>> CreateInitOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ RefPtr<UniversalDirectoryLock> aDirectoryLock) {
+ return MakeRefPtr<InitOp>(std::move(aQuotaManager),
+ std::move(aDirectoryLock));
+}
+
+RefPtr<ResolvableNormalOriginOp<bool>> CreateInitTemporaryStorageOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ RefPtr<UniversalDirectoryLock> aDirectoryLock) {
+ return MakeRefPtr<InitTemporaryStorageOp>(std::move(aQuotaManager),
+ std::move(aDirectoryLock));
+}
+
+RefPtr<QuotaRequestBase> CreateInitializePersistentOriginOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams) {
+ return MakeRefPtr<InitializePersistentOriginOp>(std::move(aQuotaManager),
+ aParams);
+}
+
+RefPtr<QuotaRequestBase> CreateInitializeTemporaryOriginOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams) {
+ return MakeRefPtr<InitializeTemporaryOriginOp>(std::move(aQuotaManager),
+ aParams);
+}
+
+RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializePersistentClientOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
+ const Client::Type aClientType) {
+ return MakeRefPtr<InitializePersistentClientOp>(std::move(aQuotaManager),
+ aPrincipalInfo, aClientType);
+}
+
+RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializeTemporaryClientOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
+ const Client::Type aClientType) {
+ return MakeRefPtr<InitializeTemporaryClientOp>(
+ std::move(aQuotaManager), aPersistenceType, aPrincipalInfo, aClientType);
+}
+
+RefPtr<QuotaRequestBase> CreateGetFullOriginMetadataOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const GetFullOriginMetadataParams& aParams) {
+ return MakeRefPtr<GetFullOriginMetadataOp>(std::move(aQuotaManager), aParams);
+}
+
+RefPtr<ResolvableNormalOriginOp<bool>> CreateClearStorageOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
+ return MakeRefPtr<ClearStorageOp>(std::move(aQuotaManager));
+}
+
+RefPtr<ResolvableNormalOriginOp<bool>> CreateClearOriginOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const Maybe<PersistenceType>& aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo,
+ const Maybe<Client::Type>& aClientType) {
+ return MakeRefPtr<ClearOriginOp>(std::move(aQuotaManager), aPersistenceType,
+ aPrincipalInfo, aClientType);
+}
+
+RefPtr<ResolvableNormalOriginOp<bool>> CreateClearStoragesForOriginPrefixOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const Maybe<PersistenceType>& aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo) {
+ return MakeRefPtr<ClearStoragesForOriginPrefixOp>(
+ std::move(aQuotaManager), aPersistenceType, aPrincipalInfo);
+}
+
+RefPtr<ResolvableNormalOriginOp<bool>> CreateClearDataOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const OriginAttributesPattern& aPattern) {
+ return MakeRefPtr<ClearDataOp>(std::move(aQuotaManager), aPattern);
+}
+
+RefPtr<QuotaRequestBase> CreateResetOriginOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams) {
+ return MakeRefPtr<ResetOriginOp>(std::move(aQuotaManager), aParams);
+}
+
+RefPtr<QuotaRequestBase> CreatePersistedOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams) {
+ return MakeRefPtr<PersistedOp>(std::move(aQuotaManager), aParams);
+}
+
+RefPtr<QuotaRequestBase> CreatePersistOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams) {
+ return MakeRefPtr<PersistOp>(std::move(aQuotaManager), aParams);
+}
+
+RefPtr<QuotaRequestBase> CreateEstimateOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const EstimateParams& aParams) {
+ return MakeRefPtr<EstimateOp>(std::move(aQuotaManager), aParams);
+}
+
+RefPtr<QuotaRequestBase> CreateListOriginsOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
+ return MakeRefPtr<ListOriginsOp>(std::move(aQuotaManager));
+}
+
+template <class Base>
+RefPtr<BoolPromise> OpenStorageDirectoryHelper<Base>::OpenStorageDirectory(
+ const Nullable<PersistenceType>& aPersistenceType,
+ const OriginScope& aOriginScope, const Nullable<Client::Type>& aClientType,
+ bool aExclusive) {
+ return Base::mQuotaManager
+ ->OpenStorageDirectory(aPersistenceType, aOriginScope, aClientType,
+ aExclusive)
+ ->Then(GetCurrentSerialEventTarget(), __func__,
+ [self = RefPtr(this)](
+ UniversalDirectoryLockPromise::ResolveOrRejectValue&& aValue) {
+ if (aValue.IsReject()) {
+ return BoolPromise::CreateAndReject(aValue.RejectValue(),
+ __func__);
+ }
+
+ self->mDirectoryLock = std::move(aValue.ResolveValue());
+
+ return BoolPromise::CreateAndResolve(true, __func__);
+ });
+}
+
+RefPtr<BoolPromise> FinalizeOriginEvictionOp::Open() {
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(!mLocks.IsEmpty());
+
+ return BoolPromise::CreateAndResolve(true, __func__);
+}
+
+nsresult FinalizeOriginEvictionOp::DoDirectoryWork(
+ QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ AUTO_PROFILER_LABEL("FinalizeOriginEvictionOp::DoDirectoryWork", OTHER);
+
+ for (const auto& lock : mLocks) {
+ aQuotaManager.OriginClearCompleted(
+ lock->GetPersistenceType(), lock->Origin(), Nullable<Client::Type>());
+ }
+
+ return NS_OK;
+}
+
+void FinalizeOriginEvictionOp::UnblockOpen() {
+ AssertIsOnOwningThread();
+
+#ifdef DEBUG
+ NoteActorDestroyed();
+#endif
+
+ mLocks.Clear();
+}
+
+RefPtr<BoolPromise> SaveOriginAccessTimeOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ return OpenStorageDirectory(
+ Nullable<PersistenceType>(mOriginMetadata.mPersistenceType),
+ OriginScope::FromOrigin(mOriginMetadata.mOrigin),
+ Nullable<Client::Type>(),
+ /* aExclusive */ false);
+}
+
+nsresult SaveOriginAccessTimeOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+ aQuotaManager.AssertStorageIsInitializedInternal();
+
+ AUTO_PROFILER_LABEL("SaveOriginAccessTimeOp::DoDirectoryWork", OTHER);
+
+ QM_TRY(MOZ_TO_RESULT(!QuotaManager::IsShuttingDown()), NS_ERROR_ABORT);
+
+ QM_TRY_INSPECT(const auto& file,
+ aQuotaManager.GetOriginDirectory(mOriginMetadata));
+
+ // The origin directory might not exist
+ // anymore, because it was deleted by a clear operation.
+ QM_TRY_INSPECT(const bool& exists, MOZ_TO_RESULT_INVOKE_MEMBER(file, Exists));
+
+ if (exists) {
+ QM_TRY(MOZ_TO_RESULT(file->Append(nsLiteralString(METADATA_V2_FILE_NAME))));
+
+ QM_TRY_INSPECT(const auto& stream,
+ GetBinaryOutputStream(*file, FileFlag::Update));
+ MOZ_ASSERT(stream);
+
+ QM_TRY(MOZ_TO_RESULT(stream->Write64(mTimestamp)));
+ }
+
+ return NS_OK;
+}
+
+void SaveOriginAccessTimeOp::SendResults() {
+#ifdef DEBUG
+ NoteActorDestroyed();
+#endif
+}
+
+void SaveOriginAccessTimeOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+RefPtr<BoolPromise> ClearPrivateRepositoryOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ return OpenStorageDirectory(
+ Nullable<PersistenceType>(PERSISTENCE_TYPE_PRIVATE),
+ OriginScope::FromNull(), Nullable<Client::Type>(),
+ /* aExclusive */ true);
+}
+
+nsresult ClearPrivateRepositoryOp::DoDirectoryWork(
+ QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+ aQuotaManager.AssertStorageIsInitializedInternal();
+
+ AUTO_PROFILER_LABEL("ClearPrivateRepositoryOp::DoDirectoryWork", OTHER);
+
+ QM_TRY_INSPECT(
+ const auto& directory,
+ QM_NewLocalFile(aQuotaManager.GetStoragePath(PERSISTENCE_TYPE_PRIVATE)));
+
+ nsresult rv = directory->Remove(true);
+ if (rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
+ // This should never fail if we've closed all storage connections
+ // correctly...
+ MOZ_ASSERT(false, "Failed to remove directory!");
+ }
+
+ aQuotaManager.RemoveQuotaForRepository(PERSISTENCE_TYPE_PRIVATE);
+
+ aQuotaManager.RepositoryClearCompleted(PERSISTENCE_TYPE_PRIVATE);
+
+ return NS_OK;
+}
+
+void ClearPrivateRepositoryOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+RefPtr<BoolPromise> ShutdownStorageOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ // Clear directory lock tables (which also saves origin access time) before
+ // acquiring the exclusive lock below. Otherwise, saving of origin access
+ // time would be scheduled after storage shutdown and that would initialize
+ // storage again in the end.
+ mQuotaManager->ClearDirectoryLockTables();
+
+ mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
+ Nullable<PersistenceType>(), OriginScope::FromNull(),
+ Nullable<Client::Type>(),
+ /* aExclusive */ true);
+
+ return mDirectoryLock->Acquire();
+}
+
+#ifdef DEBUG
+nsresult ShutdownStorageOp::DirectoryOpen() {
+ AssertIsOnBackgroundThread();
+ MOZ_ASSERT(mDirectoryLock);
+ mDirectoryLock->AssertIsAcquiredExclusively();
+
+ return NormalOriginOperationBase::DirectoryOpen();
+}
+#endif
+
+nsresult ShutdownStorageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ AUTO_PROFILER_LABEL("ShutdownStorageOp::DoDirectoryWork", OTHER);
+
+ aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
+ "ShutdownStorageOp::DoDirectoryWork -> ShutdownStorageInternal."_ns);
+
+ aQuotaManager.ShutdownStorageInternal();
+
+ return NS_OK;
+}
+
+void ShutdownStorageOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+nsresult TraverseRepositoryHelper::TraverseRepository(
+ QuotaManager& aQuotaManager, PersistenceType aPersistenceType) {
+ AssertIsOnIOThread();
+
+ QM_TRY_INSPECT(
+ const auto& directory,
+ QM_NewLocalFile(aQuotaManager.GetStoragePath(aPersistenceType)));
+
+ QM_TRY_INSPECT(const bool& exists,
+ MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
+
+ if (!exists) {
+ return NS_OK;
+ }
+
+ QM_TRY(CollectEachFileAtomicCancelable(
+ *directory, GetIsCanceledFlag(),
+ [this, aPersistenceType, &aQuotaManager,
+ persistent = aPersistenceType == PERSISTENCE_TYPE_PERSISTENT](
+ const nsCOMPtr<nsIFile>& originDir) -> Result<Ok, nsresult> {
+ QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*originDir));
+
+ switch (dirEntryKind) {
+ case nsIFileKind::ExistsAsDirectory:
+ QM_TRY(MOZ_TO_RESULT(ProcessOrigin(aQuotaManager, *originDir,
+ persistent, aPersistenceType)));
+ break;
+
+ case nsIFileKind::ExistsAsFile: {
+ QM_TRY_INSPECT(const auto& leafName,
+ MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
+ nsAutoString, originDir, GetLeafName));
+
+ // Unknown files during getting usages are allowed. Just warn if we
+ // find them.
+ if (!IsOSMetadata(leafName)) {
+ UNKNOWN_FILE_WARNING(leafName);
+ }
+
+ break;
+ }
+
+ case nsIFileKind::DoesNotExist:
+ // Ignore files that got removed externally while iterating.
+ break;
+ }
+
+ return Ok{};
+ }));
+
+ return NS_OK;
+}
+
+GetUsageOp::GetUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const UsageRequestParams& aParams)
+ : OpenStorageDirectoryHelper(std::move(aQuotaManager),
+ "dom::quota::GetUsageOp"),
+ mGetAll(aParams.get_AllUsageParams().getAll()) {
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(aParams.type() == UsageRequestParams::TAllUsageParams);
+}
+
+void GetUsageOp::ProcessOriginInternal(QuotaManager* aQuotaManager,
+ const PersistenceType aPersistenceType,
+ const nsACString& aOrigin,
+ const int64_t aTimestamp,
+ const bool aPersisted,
+ const uint64_t aUsage) {
+ if (!mGetAll && aQuotaManager->IsOriginInternal(aOrigin)) {
+ return;
+ }
+
+ // We can't store pointers to OriginUsage objects in the hashtable
+ // since AppendElement() reallocates its internal array buffer as number
+ // of elements grows.
+ const auto& originUsage =
+ mOriginUsagesIndex.WithEntryHandle(aOrigin, [&](auto&& entry) {
+ if (entry) {
+ return WrapNotNullUnchecked(&mOriginUsages[entry.Data()]);
+ }
+
+ entry.Insert(mOriginUsages.Length());
+
+ return mOriginUsages.EmplaceBack(nsCString{aOrigin}, false, 0, 0);
+ });
+
+ if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) {
+ originUsage->persisted() = aPersisted;
+ }
+
+ originUsage->usage() = originUsage->usage() + aUsage;
+
+ originUsage->lastAccessed() =
+ std::max<int64_t>(originUsage->lastAccessed(), aTimestamp);
+}
+
+const Atomic<bool>& GetUsageOp::GetIsCanceledFlag() {
+ AssertIsOnIOThread();
+
+ return mCanceled;
+}
+
+// XXX Remove aPersistent
+// XXX Remove aPersistenceType once GetUsageForOrigin uses the persistence
+// type from OriginMetadata
+nsresult GetUsageOp::ProcessOrigin(QuotaManager& aQuotaManager,
+ nsIFile& aOriginDir, const bool aPersistent,
+ const PersistenceType aPersistenceType) {
+ AssertIsOnIOThread();
+
+ QM_TRY_UNWRAP(auto maybeMetadata,
+ QM_OR_ELSE_WARN_IF(
+ // Expression
+ aQuotaManager.LoadFullOriginMetadataWithRestore(&aOriginDir)
+ .map([](auto metadata) -> Maybe<FullOriginMetadata> {
+ return Some(std::move(metadata));
+ }),
+ // Predicate.
+ IsSpecificError<NS_ERROR_MALFORMED_URI>,
+ // Fallback.
+ ErrToDefaultOk<Maybe<FullOriginMetadata>>));
+
+ if (!maybeMetadata) {
+ // Unknown directories during getting usage are allowed. Just warn if we
+ // find them.
+ QM_TRY_INSPECT(const auto& leafName,
+ MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, aOriginDir,
+ GetLeafName));
+
+ UNKNOWN_FILE_WARNING(leafName);
+ return NS_OK;
+ }
+
+ auto metadata = maybeMetadata.extract();
+
+ QM_TRY_INSPECT(const auto& usageInfo,
+ GetUsageForOrigin(aQuotaManager, aPersistenceType, metadata));
+
+ ProcessOriginInternal(&aQuotaManager, aPersistenceType, metadata.mOrigin,
+ metadata.mLastAccessTime, metadata.mPersisted,
+ usageInfo.TotalUsage().valueOr(0));
+
+ return NS_OK;
+}
+
+RefPtr<BoolPromise> GetUsageOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ return OpenStorageDirectory(Nullable<PersistenceType>(),
+ OriginScope::FromNull(), Nullable<Client::Type>(),
+ /* aExclusive */ false);
+}
+
+nsresult GetUsageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+ aQuotaManager.AssertStorageIsInitializedInternal();
+
+ AUTO_PROFILER_LABEL("GetUsageOp::DoDirectoryWork", OTHER);
+
+ nsresult rv;
+
+ for (const PersistenceType type : kAllPersistenceTypes) {
+ rv = TraverseRepository(aQuotaManager, type);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ }
+
+ // TraverseRepository above only consulted the filesystem. We also need to
+ // consider origins which may have pending quota usage, such as buffered
+ // LocalStorage writes for an origin which didn't previously have any
+ // LocalStorage data.
+
+ aQuotaManager.CollectPendingOriginsForListing(
+ [this, &aQuotaManager](const auto& originInfo) {
+ ProcessOriginInternal(
+ &aQuotaManager, originInfo->GetGroupInfo()->GetPersistenceType(),
+ originInfo->Origin(), originInfo->LockedAccessTime(),
+ originInfo->LockedPersisted(), originInfo->LockedUsage());
+ });
+
+ return NS_OK;
+}
+
+void GetUsageOp::GetResponse(UsageRequestResponse& aResponse) {
+ AssertIsOnOwningThread();
+
+ aResponse = AllUsageResponse();
+
+ aResponse.get_AllUsageResponse().originUsages() = std::move(mOriginUsages);
+}
+
+void GetUsageOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+GetOriginUsageOp::GetOriginUsageOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const UsageRequestParams& aParams)
+ : OpenStorageDirectoryHelper(std::move(aQuotaManager),
+ "dom::quota::GetOriginUsageOp"),
+ mParams(aParams.get_OriginUsageParams()) {
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(aParams.type() == UsageRequestParams::TOriginUsageParams);
+
+ // Overwrite GetOriginUsageOp default values.
+ mFromMemory = mParams.fromMemory();
+}
+
+nsresult GetOriginUsageOp::DoInit(QuotaManager& aQuotaManager) {
+ AssertIsOnOwningThread();
+
+ QM_TRY_UNWRAP(
+ mPrincipalMetadata,
+ aQuotaManager.GetInfoFromValidatedPrincipalInfo(mParams.principalInfo()));
+
+ mPrincipalMetadata.AssertInvariants();
+
+ return NS_OK;
+}
+
+RefPtr<BoolPromise> GetOriginUsageOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ return OpenStorageDirectory(
+ Nullable<PersistenceType>(),
+ OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
+ Nullable<Client::Type>(),
+ /* aExclusive */ false);
+}
+
+nsresult GetOriginUsageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+ aQuotaManager.AssertStorageIsInitializedInternal();
+ MOZ_ASSERT(mUsageInfo.TotalUsage().isNothing());
+
+ AUTO_PROFILER_LABEL("GetOriginUsageOp::DoDirectoryWork", OTHER);
+
+ if (mFromMemory) {
+ // Ensure temporary storage is initialized. If temporary storage hasn't been
+ // initialized yet, the method will initialize it by traversing the
+ // repositories for temporary and default storage (including our origin).
+ QM_TRY(MOZ_TO_RESULT(
+ aQuotaManager.EnsureTemporaryStorageIsInitializedInternal()));
+
+ // Get cached usage (the method doesn't have to stat any files). File usage
+ // is not tracked in memory separately, so just add to the database usage.
+ mUsageInfo += DatabaseUsageType(
+ Some(aQuotaManager.GetOriginUsage(mPrincipalMetadata)));
+
+ return NS_OK;
+ }
+
+ // Add all the persistent/temporary/default storage files we care about.
+ for (const PersistenceType type : kAllPersistenceTypes) {
+ const OriginMetadata originMetadata = {mPrincipalMetadata, type};
+
+ auto usageInfoOrErr =
+ GetUsageForOrigin(aQuotaManager, type, originMetadata);
+ if (NS_WARN_IF(usageInfoOrErr.isErr())) {
+ return usageInfoOrErr.unwrapErr();
+ }
+
+ mUsageInfo += usageInfoOrErr.unwrap();
+ }
+
+ return NS_OK;
+}
+
+void GetOriginUsageOp::GetResponse(UsageRequestResponse& aResponse) {
+ AssertIsOnOwningThread();
+
+ OriginUsageResponse usageResponse;
+
+ usageResponse.usageInfo() = mUsageInfo;
+
+ aResponse = usageResponse;
+}
+
+void GetOriginUsageOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+StorageNameOp::StorageNameOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
+ : QuotaRequestBase(std::move(aQuotaManager), "dom::quota::StorageNameOp") {
+ AssertIsOnOwningThread();
+}
+
+RefPtr<BoolPromise> StorageNameOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ return BoolPromise::CreateAndResolve(true, __func__);
+}
+
+nsresult StorageNameOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ AUTO_PROFILER_LABEL("StorageNameOp::DoDirectoryWork", OTHER);
+
+ mName = aQuotaManager.GetStorageName();
+
+ return NS_OK;
+}
+
+void StorageNameOp::GetResponse(RequestResponse& aResponse) {
+ AssertIsOnOwningThread();
+
+ StorageNameResponse storageNameResponse;
+
+ storageNameResponse.name() = mName;
+
+ aResponse = storageNameResponse;
+}
+
+void StorageNameOp::CloseDirectory() { AssertIsOnOwningThread(); }
+
+InitializedRequestBase::InitializedRequestBase(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName)
+ : ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
+ mInitialized(false) {
+ AssertIsOnOwningThread();
+}
+
+RefPtr<BoolPromise> InitializedRequestBase::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ return BoolPromise::CreateAndResolve(true, __func__);
+}
+
+void InitializedRequestBase::CloseDirectory() { AssertIsOnOwningThread(); }
+
+nsresult StorageInitializedOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ AUTO_PROFILER_LABEL("StorageInitializedOp::DoDirectoryWork", OTHER);
+
+ mInitialized = aQuotaManager.IsStorageInitializedInternal();
+
+ return NS_OK;
+}
+
+bool StorageInitializedOp::GetResolveValue() {
+ AssertIsOnOwningThread();
+
+ return mInitialized;
+}
+
+nsresult TemporaryStorageInitializedOp::DoDirectoryWork(
+ QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ AUTO_PROFILER_LABEL("TemporaryStorageInitializedOp::DoDirectoryWork", OTHER);
+
+ mInitialized = aQuotaManager.IsTemporaryStorageInitializedInternal();
+
+ return NS_OK;
+}
+
+bool TemporaryStorageInitializedOp::GetResolveValue() {
+ AssertIsOnOwningThread();
+
+ return mInitialized;
+}
+
+InitOp::InitOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ RefPtr<UniversalDirectoryLock> aDirectoryLock)
+ : ResolvableNormalOriginOp(std::move(aQuotaManager), "dom::quota::InitOp"),
+ mDirectoryLock(std::move(aDirectoryLock)) {
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(mDirectoryLock);
+}
+
+RefPtr<BoolPromise> InitOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(mDirectoryLock);
+
+ return BoolPromise::CreateAndResolve(true, __func__);
+}
+
+nsresult InitOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ AUTO_PROFILER_LABEL("InitOp::DoDirectoryWork", OTHER);
+
+ QM_TRY(MOZ_TO_RESULT(aQuotaManager.EnsureStorageIsInitializedInternal()));
+
+ return NS_OK;
+}
+
+bool InitOp::GetResolveValue() { return true; }
+
+void InitOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+InitTemporaryStorageOp::InitTemporaryStorageOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ RefPtr<UniversalDirectoryLock> aDirectoryLock)
+ : ResolvableNormalOriginOp(std::move(aQuotaManager),
+ "dom::quota::InitTemporaryStorageOp"),
+ mDirectoryLock(std::move(aDirectoryLock)) {
+ AssertIsOnOwningThread();
+}
+
+RefPtr<BoolPromise> InitTemporaryStorageOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(mDirectoryLock);
+
+ return BoolPromise::CreateAndResolve(true, __func__);
+}
+
+nsresult InitTemporaryStorageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ AUTO_PROFILER_LABEL("InitTemporaryStorageOp::DoDirectoryWork", OTHER);
+
+ QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
+ NS_ERROR_NOT_INITIALIZED);
+
+ QM_TRY(MOZ_TO_RESULT(
+ aQuotaManager.EnsureTemporaryStorageIsInitializedInternal()));
+
+ return NS_OK;
+}
+
+bool InitTemporaryStorageOp::GetResolveValue() {
+ AssertIsOnOwningThread();
+
+ return true;
+}
+
+void InitTemporaryStorageOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+InitializeOriginRequestBase::InitializeOriginRequestBase(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
+ const PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo)
+ : QuotaRequestBase(std::move(aQuotaManager), aName),
+ mPrincipalInfo(aPrincipalInfo),
+ mPersistenceType(aPersistenceType),
+ mCreated(false) {
+ AssertIsOnOwningThread();
+}
+
+nsresult InitializeOriginRequestBase::DoInit(QuotaManager& aQuotaManager) {
+ AssertIsOnOwningThread();
+
+ QM_TRY_UNWRAP(
+ mPrincipalMetadata,
+ aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
+
+ mPrincipalMetadata.AssertInvariants();
+
+ return NS_OK;
+}
+
+RefPtr<BoolPromise> InitializeOriginRequestBase::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
+ Nullable<PersistenceType>(mPersistenceType),
+ OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
+ Nullable<Client::Type>(), /* aExclusive */ false);
+
+ return mDirectoryLock->Acquire();
+}
+
+void InitializeOriginRequestBase::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+InitializePersistentOriginOp::InitializePersistentOriginOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams)
+ : InitializeOriginRequestBase(
+ std::move(aQuotaManager), "dom::quota::InitializePersistentOriginOp",
+ PERSISTENCE_TYPE_PERSISTENT,
+ aParams.get_InitializePersistentOriginParams().principalInfo()) {
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(aParams.type() ==
+ RequestParams::TInitializePersistentOriginParams);
+}
+
+nsresult InitializePersistentOriginOp::DoDirectoryWork(
+ QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ AUTO_PROFILER_LABEL("InitializePersistentOriginOp::DoDirectoryWork", OTHER);
+
+ QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
+ NS_ERROR_NOT_INITIALIZED);
+
+ QM_TRY_UNWRAP(mCreated,
+ (aQuotaManager
+ .EnsurePersistentOriginIsInitialized(OriginMetadata{
+ mPrincipalMetadata, PERSISTENCE_TYPE_PERSISTENT})
+ .map([](const auto& res) { return res.second; })));
+
+ return NS_OK;
+}
+
+void InitializePersistentOriginOp::GetResponse(RequestResponse& aResponse) {
+ AssertIsOnOwningThread();
+
+ aResponse = InitializePersistentOriginResponse(mCreated);
+}
+
+InitializeTemporaryOriginOp::InitializeTemporaryOriginOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams)
+ : InitializeOriginRequestBase(
+ std::move(aQuotaManager), "dom::quota::InitializeTemporaryOriginOp",
+ aParams.get_InitializeTemporaryOriginParams().persistenceType(),
+ aParams.get_InitializeTemporaryOriginParams().principalInfo()) {
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(aParams.type() == RequestParams::TInitializeTemporaryOriginParams);
+}
+
+nsresult InitializeTemporaryOriginOp::DoDirectoryWork(
+ QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ AUTO_PROFILER_LABEL("InitializeTemporaryOriginOp::DoDirectoryWork", OTHER);
+
+ QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
+ NS_ERROR_NOT_INITIALIZED);
+
+ QM_TRY(OkIf(aQuotaManager.IsTemporaryStorageInitializedInternal()),
+ NS_ERROR_NOT_INITIALIZED);
+
+ QM_TRY_UNWRAP(mCreated,
+ (aQuotaManager
+ .EnsureTemporaryOriginIsInitialized(
+ mPersistenceType,
+ OriginMetadata{mPrincipalMetadata, mPersistenceType})
+ .map([](const auto& res) { return res.second; })));
+
+ return NS_OK;
+}
+
+void InitializeTemporaryOriginOp::GetResponse(RequestResponse& aResponse) {
+ AssertIsOnOwningThread();
+
+ aResponse = InitializeTemporaryOriginResponse(mCreated);
+}
+
+InitializeClientBase::InitializeClientBase(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
+ const PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
+ Client::Type aClientType)
+ : ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
+ mPrincipalInfo(aPrincipalInfo),
+ mPersistenceType(aPersistenceType),
+ mClientType(aClientType),
+ mCreated(false) {
+ AssertIsOnOwningThread();
+}
+
+nsresult InitializeClientBase::DoInit(QuotaManager& aQuotaManager) {
+ AssertIsOnOwningThread();
+
+ QM_TRY_UNWRAP(
+ PrincipalMetadata principalMetadata,
+ aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
+
+ principalMetadata.AssertInvariants();
+
+ mClientMetadata = {
+ OriginMetadata{std::move(principalMetadata), mPersistenceType},
+ mClientType};
+
+ return NS_OK;
+}
+
+RefPtr<BoolPromise> InitializeClientBase::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
+ Nullable(mPersistenceType),
+ OriginScope::FromOrigin(mClientMetadata.mOrigin),
+ Nullable(mClientMetadata.mClientType), /* aExclusive */ false);
+
+ return mDirectoryLock->Acquire();
+}
+
+void InitializeClientBase::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+InitializePersistentClientOp::InitializePersistentClientOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const PrincipalInfo& aPrincipalInfo, Client::Type aClientType)
+ : InitializeClientBase(
+ std::move(aQuotaManager), "dom::quota::InitializePersistentClientOp",
+ PERSISTENCE_TYPE_PERSISTENT, aPrincipalInfo, aClientType) {
+ AssertIsOnOwningThread();
+}
+
+nsresult InitializePersistentClientOp::DoDirectoryWork(
+ QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ AUTO_PROFILER_LABEL("InitializePersistentClientOp::DoDirectoryWork", OTHER);
+
+ QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsStorageInitializedInternal()),
+ NS_ERROR_FAILURE);
+
+ QM_TRY(
+ MOZ_TO_RESULT(aQuotaManager.IsOriginInitialized(mClientMetadata.mOrigin)),
+ NS_ERROR_FAILURE);
+
+ QM_TRY_UNWRAP(
+ mCreated,
+ (aQuotaManager.EnsurePersistentClientIsInitialized(mClientMetadata)
+ .map([](const auto& res) { return res.second; })));
+
+ return NS_OK;
+}
+
+bool InitializePersistentClientOp::GetResolveValue() {
+ AssertIsOnOwningThread();
+
+ return mCreated;
+}
+
+InitializeTemporaryClientOp::InitializeTemporaryClientOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
+ Client::Type aClientType)
+ : InitializeClientBase(std::move(aQuotaManager),
+ "dom::quota::InitializeTemporaryClientOp",
+ aPersistenceType, aPrincipalInfo, aClientType) {
+ AssertIsOnOwningThread();
+}
+
+nsresult InitializeTemporaryClientOp::DoDirectoryWork(
+ QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ AUTO_PROFILER_LABEL("InitializeTemporaryClientOp::DoDirectoryWork", OTHER);
+
+ QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsStorageInitializedInternal()),
+ NS_ERROR_FAILURE);
+
+ QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsTemporaryStorageInitializedInternal()),
+ NS_ERROR_FAILURE);
+
+ QM_TRY(MOZ_TO_RESULT(
+ aQuotaManager.IsTemporaryOriginInitialized(mClientMetadata)),
+ NS_ERROR_FAILURE);
+
+ QM_TRY_UNWRAP(
+ mCreated,
+ (aQuotaManager.EnsureTemporaryClientIsInitialized(mClientMetadata)
+ .map([](const auto& res) { return res.second; })));
+
+ return NS_OK;
+}
+
+bool InitializeTemporaryClientOp::GetResolveValue() {
+ AssertIsOnOwningThread();
+
+ return mCreated;
+}
+
+GetFullOriginMetadataOp::GetFullOriginMetadataOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const GetFullOriginMetadataParams& aParams)
+ : OpenStorageDirectoryHelper(std::move(aQuotaManager),
+ "dom::quota::GetFullOriginMetadataOp"),
+ mParams(aParams) {
+ AssertIsOnOwningThread();
+}
+
+nsresult GetFullOriginMetadataOp::DoInit(QuotaManager& aQuotaManager) {
+ AssertIsOnOwningThread();
+
+ QM_TRY_UNWRAP(
+ PrincipalMetadata principalMetadata,
+ aQuotaManager.GetInfoFromValidatedPrincipalInfo(mParams.principalInfo()));
+
+ principalMetadata.AssertInvariants();
+
+ mOriginMetadata = {std::move(principalMetadata), mParams.persistenceType()};
+
+ return NS_OK;
+}
+
+RefPtr<BoolPromise> GetFullOriginMetadataOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ return OpenStorageDirectory(
+ Nullable<PersistenceType>(mOriginMetadata.mPersistenceType),
+ OriginScope::FromOrigin(mOriginMetadata.mOrigin),
+ Nullable<Client::Type>(),
+ /* aExclusive */ false);
+}
+
+nsresult GetFullOriginMetadataOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+ aQuotaManager.AssertStorageIsInitializedInternal();
+
+ AUTO_PROFILER_LABEL("GetFullOriginMetadataOp::DoDirectoryWork", OTHER);
+
+ // Ensure temporary storage is initialized. If temporary storage hasn't
+ // been initialized yet, the method will initialize it by traversing the
+ // repositories for temporary and default storage (including our origin).
+ QM_TRY(MOZ_TO_RESULT(
+ aQuotaManager.EnsureTemporaryStorageIsInitializedInternal()));
+
+ // Get metadata cached in memory (the method doesn't have to stat any
+ // files).
+ mMaybeFullOriginMetadata =
+ aQuotaManager.GetFullOriginMetadata(mOriginMetadata);
+
+ return NS_OK;
+}
+
+void GetFullOriginMetadataOp::GetResponse(RequestResponse& aResponse) {
+ AssertIsOnOwningThread();
+
+ aResponse = GetFullOriginMetadataResponse();
+ aResponse.get_GetFullOriginMetadataResponse().maybeFullOriginMetadata() =
+ std::move(mMaybeFullOriginMetadata);
+}
+
+void GetFullOriginMetadataOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+ClearStorageOp::ClearStorageOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
+ : OpenStorageDirectoryHelper(std::move(aQuotaManager),
+ "dom::quota::ClearStorageOp") {
+ AssertIsOnOwningThread();
+}
+
+void ClearStorageOp::DeleteFiles(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ nsresult rv = aQuotaManager.AboutToClearOrigins(Nullable<PersistenceType>(),
+ OriginScope::FromNull(),
+ Nullable<Client::Type>());
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return;
+ }
+
+ auto directoryOrErr = QM_NewLocalFile(aQuotaManager.GetStoragePath());
+ if (NS_WARN_IF(directoryOrErr.isErr())) {
+ return;
+ }
+
+ nsCOMPtr<nsIFile> directory = directoryOrErr.unwrap();
+
+ rv = directory->Remove(true);
+ if (rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
+ // This should never fail if we've closed all storage connections
+ // correctly...
+ MOZ_ASSERT(false, "Failed to remove storage directory!");
+ }
+}
+
+void ClearStorageOp::DeleteStorageFile(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ QM_TRY_INSPECT(const auto& storageFile,
+ QM_NewLocalFile(aQuotaManager.GetBasePath()), QM_VOID);
+
+ QM_TRY(MOZ_TO_RESULT(storageFile->Append(aQuotaManager.GetStorageName() +
+ kSQLiteSuffix)),
+ QM_VOID);
+
+ const nsresult rv = storageFile->Remove(true);
+ if (rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
+ // This should never fail if we've closed the storage connection
+ // correctly...
+ MOZ_ASSERT(false, "Failed to remove storage file!");
+ }
+}
+
+RefPtr<BoolPromise> ClearStorageOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ // Clear directory lock tables (which also saves origin access time) before
+ // acquiring the exclusive lock below. Otherwise, saving of origin access
+ // time would be scheduled after storage clearing and that would initialize
+ // storage again in the end.
+ mQuotaManager->ClearDirectoryLockTables();
+
+ return OpenStorageDirectory(Nullable<PersistenceType>(),
+ OriginScope::FromNull(), Nullable<Client::Type>(),
+ /* aExclusive */ true);
+}
+
+nsresult ClearStorageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+ aQuotaManager.AssertStorageIsInitializedInternal();
+
+ AUTO_PROFILER_LABEL("ClearStorageOp::DoDirectoryWork", OTHER);
+
+ DeleteFiles(aQuotaManager);
+
+ aQuotaManager.RemoveQuota();
+
+ aQuotaManager.ShutdownStorageInternal();
+
+ DeleteStorageFile(aQuotaManager);
+
+ return NS_OK;
+}
+
+bool ClearStorageOp::GetResolveValue() {
+ AssertIsOnOwningThread();
+
+ return true;
+}
+
+void ClearStorageOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
+ const OriginMetadata& aOriginMetadata,
+ const Nullable<Client::Type>& aClientType) {
+ AssertIsOnIOThread();
+
+ DeleteFilesInternal(
+ aQuotaManager, aOriginMetadata.mPersistenceType,
+ OriginScope::FromOrigin(aOriginMetadata.mOrigin), aClientType,
+ [&aQuotaManager, &aOriginMetadata](
+ const std::function<Result<Ok, nsresult>(nsCOMPtr<nsIFile>&&)>& aBody)
+ -> Result<Ok, nsresult> {
+ QM_TRY_UNWRAP(auto directory,
+ aQuotaManager.GetOriginDirectory(aOriginMetadata));
+
+ QM_TRY_INSPECT(const bool& exists,
+ MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
+
+ if (!exists) {
+ return Ok{};
+ }
+
+ QM_TRY_RETURN(aBody(std::move(directory)));
+ });
+}
+
+void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
+ PersistenceType aPersistenceType,
+ const OriginScope& aOriginScope,
+ const Nullable<Client::Type>& aClientType) {
+ AssertIsOnIOThread();
+
+ DeleteFilesInternal(
+ aQuotaManager, aPersistenceType, aOriginScope, aClientType,
+ [&aQuotaManager, &aPersistenceType](
+ const std::function<Result<Ok, nsresult>(nsCOMPtr<nsIFile>&&)>& aBody)
+ -> Result<Ok, nsresult> {
+ QM_TRY_INSPECT(
+ const auto& directory,
+ QM_NewLocalFile(aQuotaManager.GetStoragePath(aPersistenceType)));
+
+ QM_TRY_INSPECT(const bool& exists,
+ MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
+
+ if (!exists) {
+ return Ok{};
+ }
+
+ QM_TRY_RETURN(CollectEachFile(*directory, aBody));
+ });
+}
+
+template <typename FileCollector>
+void ClearRequestBase::DeleteFilesInternal(
+ QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
+ const OriginScope& aOriginScope, const Nullable<Client::Type>& aClientType,
+ const FileCollector& aFileCollector) {
+ AssertIsOnIOThread();
+
+ QM_TRY(MOZ_TO_RESULT(aQuotaManager.AboutToClearOrigins(
+ Nullable<PersistenceType>(aPersistenceType), aOriginScope,
+ aClientType)),
+ QM_VOID);
+
+ nsTArray<nsCOMPtr<nsIFile>> directoriesForRemovalRetry;
+
+ aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
+ "ClearRequestBase: Starting deleting files"_ns);
+
+ QM_TRY(
+ aFileCollector([&aClientType, &originScope = aOriginScope,
+ aPersistenceType, &aQuotaManager,
+ &directoriesForRemovalRetry](nsCOMPtr<nsIFile>&& file)
+ -> mozilla::Result<Ok, nsresult> {
+ QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*file));
+
+ QM_TRY_INSPECT(
+ const auto& leafName,
+ MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, file, GetLeafName));
+
+ switch (dirEntryKind) {
+ case nsIFileKind::ExistsAsDirectory: {
+ QM_TRY_UNWRAP(auto maybeMetadata,
+ QM_OR_ELSE_WARN_IF(
+ // Expression
+ aQuotaManager.GetOriginMetadata(file).map(
+ [](auto metadata) -> Maybe<OriginMetadata> {
+ return Some(std::move(metadata));
+ }),
+ // Predicate.
+ IsSpecificError<NS_ERROR_MALFORMED_URI>,
+ // Fallback.
+ ErrToDefaultOk<Maybe<OriginMetadata>>));
+
+ if (!maybeMetadata) {
+ // Unknown directories during clearing are allowed. Just
+ // warn if we find them.
+ UNKNOWN_FILE_WARNING(leafName);
+ break;
+ }
+
+ auto metadata = maybeMetadata.extract();
+
+ MOZ_ASSERT(metadata.mPersistenceType == aPersistenceType);
+
+ // Skip the origin directory if it doesn't match the pattern.
+ if (!originScope.Matches(
+ OriginScope::FromOrigin(metadata.mOrigin))) {
+ break;
+ }
+
+ if (!aClientType.IsNull()) {
+ nsAutoString clientDirectoryName;
+ QM_TRY(OkIf(Client::TypeToText(aClientType.Value(),
+ clientDirectoryName, fallible)),
+ Err(NS_ERROR_FAILURE));
+
+ QM_TRY(MOZ_TO_RESULT(file->Append(clientDirectoryName)));
+
+ QM_TRY_INSPECT(const bool& exists,
+ MOZ_TO_RESULT_INVOKE_MEMBER(file, Exists));
+
+ if (!exists) {
+ break;
+ }
+ }
+
+ // We can't guarantee that this will always succeed on
+ // Windows...
+ QM_WARNONLY_TRY(
+ aQuotaManager.RemoveOriginDirectory(*file), [&](const auto&) {
+ directoriesForRemovalRetry.AppendElement(std::move(file));
+ });
+
+ const bool initialized =
+ aPersistenceType == PERSISTENCE_TYPE_PERSISTENT
+ ? aQuotaManager.IsOriginInitialized(metadata.mOrigin)
+ : aQuotaManager.IsTemporaryStorageInitializedInternal();
+
+ // If it hasn't been initialized, we don't need to update the
+ // quota and notify the removing client.
+ if (!initialized) {
+ break;
+ }
+
+ if (aPersistenceType != PERSISTENCE_TYPE_PERSISTENT) {
+ if (aClientType.IsNull()) {
+ aQuotaManager.RemoveQuotaForOrigin(aPersistenceType, metadata);
+ } else {
+ aQuotaManager.ResetUsageForClient(
+ ClientMetadata{metadata, aClientType.Value()});
+ }
+ }
+
+ aQuotaManager.OriginClearCompleted(aPersistenceType,
+ metadata.mOrigin, aClientType);
+
+ break;
+ }
+
+ case nsIFileKind::ExistsAsFile: {
+ // Unknown files during clearing are allowed. Just warn if we
+ // find them.
+ if (!IsOSMetadata(leafName)) {
+ UNKNOWN_FILE_WARNING(leafName);
+ }
+
+ break;
+ }
+
+ case nsIFileKind::DoesNotExist:
+ // Ignore files that got removed externally while iterating.
+ break;
+ }
+
+ return Ok{};
+ }),
+ QM_VOID);
+
+ // Retry removing any directories that failed to be removed earlier now.
+ //
+ // XXX This will still block this operation. We might instead dispatch a
+ // runnable to our own thread for each retry round with a timer. We must
+ // ensure that the directory lock is upheld until we complete or give up
+ // though.
+ for (uint32_t index = 0; index < 10; index++) {
+ aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
+ return nsPrintfCString(
+ "ClearRequestBase: Starting repeated directory removal #%d", index);
+ });
+
+ for (auto&& file : std::exchange(directoriesForRemovalRetry,
+ nsTArray<nsCOMPtr<nsIFile>>{})) {
+ QM_WARNONLY_TRY(
+ aQuotaManager.RemoveOriginDirectory(*file),
+ ([&directoriesForRemovalRetry, &file](const auto&) {
+ directoriesForRemovalRetry.AppendElement(std::move(file));
+ }));
+ }
+
+ aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
+ return nsPrintfCString(
+ "ClearRequestBase: Completed repeated directory removal #%d", index);
+ });
+
+ if (directoriesForRemovalRetry.IsEmpty()) {
+ break;
+ }
+
+ aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
+ return nsPrintfCString("ClearRequestBase: Before sleep #%d", index);
+ });
+
+ PR_Sleep(PR_MillisecondsToInterval(200));
+
+ aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
+ return nsPrintfCString("ClearRequestBase: After sleep #%d", index);
+ });
+ }
+
+ QM_WARNONLY_TRY(OkIf(directoriesForRemovalRetry.IsEmpty()));
+
+ aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
+ "ClearRequestBase: Completed deleting files"_ns);
+}
+
+ClearOriginOp::ClearOriginOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const mozilla::Maybe<PersistenceType>& aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo,
+ const mozilla::Maybe<Client::Type>& aClientType)
+ : ClearRequestBase(std::move(aQuotaManager), "dom::quota::ClearOriginOp"),
+ mPrincipalInfo(aPrincipalInfo),
+ mPersistenceType(aPersistenceType
+ ? Nullable<PersistenceType>(*aPersistenceType)
+ : Nullable<PersistenceType>()),
+ mClientType(aClientType ? Nullable<Client::Type>(*aClientType)
+ : Nullable<Client::Type>()) {
+ AssertIsOnOwningThread();
+}
+
+nsresult ClearOriginOp::DoInit(QuotaManager& aQuotaManager) {
+ AssertIsOnOwningThread();
+
+ QM_TRY_UNWRAP(
+ mPrincipalMetadata,
+ aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
+
+ mPrincipalMetadata.AssertInvariants();
+
+ return NS_OK;
+}
+
+RefPtr<BoolPromise> ClearOriginOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ return OpenStorageDirectory(
+ mPersistenceType, OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
+ mClientType,
+ /* aExclusive */ true);
+}
+
+nsresult ClearOriginOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+ aQuotaManager.AssertStorageIsInitializedInternal();
+
+ AUTO_PROFILER_LABEL("ClearRequestBase::DoDirectoryWork", OTHER);
+
+ if (mPersistenceType.IsNull()) {
+ for (const PersistenceType type : kAllPersistenceTypes) {
+ DeleteFiles(aQuotaManager, OriginMetadata(mPrincipalMetadata, type),
+ mClientType);
+ }
+ } else {
+ DeleteFiles(aQuotaManager,
+ OriginMetadata(mPrincipalMetadata, mPersistenceType.Value()),
+ mClientType);
+ }
+
+ return NS_OK;
+}
+
+bool ClearOriginOp::GetResolveValue() {
+ AssertIsOnOwningThread();
+
+ return true;
+}
+
+void ClearOriginOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+ClearStoragesForOriginPrefixOp::ClearStoragesForOriginPrefixOp(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const Maybe<PersistenceType>& aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo)
+ : OpenStorageDirectoryHelper(std::move(aQuotaManager),
+ "dom::quota::ClearStoragesForOriginPrefixOp"),
+ mPrefix(
+ QuotaManager::GetOriginFromValidatedPrincipalInfo(aPrincipalInfo)),
+ mPersistenceType(aPersistenceType
+ ? Nullable<PersistenceType>(*aPersistenceType)
+ : Nullable<PersistenceType>()) {
+ AssertIsOnOwningThread();
+}
+
+RefPtr<BoolPromise> ClearStoragesForOriginPrefixOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ return OpenStorageDirectory(mPersistenceType,
+ OriginScope::FromPrefix(mPrefix),
+ Nullable<Client::Type>(),
+ /* aExclusive */ true);
+}
+
+nsresult ClearStoragesForOriginPrefixOp::DoDirectoryWork(
+ QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ AUTO_PROFILER_LABEL("ClearStoragesForOriginPrefixOp::DoDirectoryWork", OTHER);
+
+ if (mPersistenceType.IsNull()) {
+ for (const PersistenceType type : kAllPersistenceTypes) {
+ DeleteFiles(aQuotaManager, type, OriginScope::FromPrefix(mPrefix),
+ Nullable<Client::Type>());
+ }
+ } else {
+ DeleteFiles(aQuotaManager, mPersistenceType.Value(),
+ OriginScope::FromPrefix(mPrefix), Nullable<Client::Type>());
+ }
+
+ return NS_OK;
+}
+
+bool ClearStoragesForOriginPrefixOp::GetResolveValue() {
+ AssertIsOnOwningThread();
+
+ return true;
+}
+
+void ClearStoragesForOriginPrefixOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+ClearDataOp::ClearDataOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const OriginAttributesPattern& aPattern)
+ : ClearRequestBase(std::move(aQuotaManager), "dom::quota::ClearDataOp"),
+ mPattern(aPattern) {}
+
+RefPtr<BoolPromise> ClearDataOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ return OpenStorageDirectory(Nullable<PersistenceType>(),
+ OriginScope::FromPattern(mPattern),
+ Nullable<Client::Type>(),
+ /* aExclusive */ true);
+}
+
+nsresult ClearDataOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ AUTO_PROFILER_LABEL("ClearRequestBase::DoDirectoryWork", OTHER);
+
+ for (const PersistenceType type : kAllPersistenceTypes) {
+ DeleteFiles(aQuotaManager, type, OriginScope::FromPattern(mPattern),
+ Nullable<Client::Type>());
+ }
+
+ return NS_OK;
+}
+
+bool ClearDataOp::GetResolveValue() {
+ AssertIsOnOwningThread();
+
+ return true;
+}
+
+void ClearDataOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+ResetOriginOp::ResetOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams)
+ : QuotaRequestBase(std::move(aQuotaManager), "dom::quota::ResetOriginOp") {
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(aParams.type() == RequestParams::TResetOriginParams);
+
+ const ClearResetOriginParams& params =
+ aParams.get_ResetOriginParams().commonParams();
+
+ mOrigin =
+ QuotaManager::GetOriginFromValidatedPrincipalInfo(params.principalInfo());
+
+ if (params.persistenceTypeIsExplicit()) {
+ mPersistenceType.SetValue(params.persistenceType());
+ }
+
+ if (params.clientTypeIsExplicit()) {
+ mClientType.SetValue(params.clientType());
+ }
+}
+
+RefPtr<BoolPromise> ResetOriginOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
+ mPersistenceType, OriginScope::FromOrigin(mOrigin), mClientType,
+ /* aExclusive */ true);
+
+ return mDirectoryLock->Acquire();
+}
+
+nsresult ResetOriginOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+
+ AUTO_PROFILER_LABEL("ResetOriginOp::DoDirectoryWork", OTHER);
+
+ // All the work is handled by NormalOriginOperationBase parent class. In
+ // this particular case, we just needed to acquire an exclusive directory
+ // lock and that's it.
+
+ return NS_OK;
+}
+
+void ResetOriginOp::GetResponse(RequestResponse& aResponse) {
+ AssertIsOnOwningThread();
+
+ aResponse = ResetOriginResponse();
+}
+
+void ResetOriginOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+PersistRequestBase::PersistRequestBase(
+ MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const PrincipalInfo& aPrincipalInfo)
+ : OpenStorageDirectoryHelper(std::move(aQuotaManager),
+ "dom::quota::PersistRequestBase"),
+ mPrincipalInfo(aPrincipalInfo) {
+ AssertIsOnOwningThread();
+}
+
+nsresult PersistRequestBase::DoInit(QuotaManager& aQuotaManager) {
+ AssertIsOnOwningThread();
+
+ // Figure out which origin we're dealing with.
+ QM_TRY_UNWRAP(
+ mPrincipalMetadata,
+ aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
+
+ mPrincipalMetadata.AssertInvariants();
+
+ return NS_OK;
+}
+
+RefPtr<BoolPromise> PersistRequestBase::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ return OpenStorageDirectory(
+ Nullable<PersistenceType>(PERSISTENCE_TYPE_DEFAULT),
+ OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
+ Nullable<Client::Type>(),
+ /* aExclusive */ false);
+}
+
+void PersistRequestBase::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+PersistedOp::PersistedOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams)
+ : PersistRequestBase(std::move(aQuotaManager),
+ aParams.get_PersistedParams().principalInfo()),
+ mPersisted(false) {
+ MOZ_ASSERT(aParams.type() == RequestParams::TPersistedParams);
+}
+
+nsresult PersistedOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+ aQuotaManager.AssertStorageIsInitializedInternal();
+
+ AUTO_PROFILER_LABEL("PersistedOp::DoDirectoryWork", OTHER);
+
+ const OriginMetadata originMetadata = {mPrincipalMetadata,
+ PERSISTENCE_TYPE_DEFAULT};
+
+ Nullable<bool> persisted = aQuotaManager.OriginPersisted(originMetadata);
+
+ if (!persisted.IsNull()) {
+ mPersisted = persisted.Value();
+ return NS_OK;
+ }
+
+ // If we get here, it means the origin hasn't been initialized yet.
+ // Try to get the persisted flag from directory metadata on disk.
+
+ QM_TRY_INSPECT(const auto& directory,
+ aQuotaManager.GetOriginDirectory(originMetadata));
+
+ QM_TRY_INSPECT(const bool& exists,
+ MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
+
+ if (exists) {
+ // Get the metadata. We only use the persisted flag.
+ QM_TRY_INSPECT(const auto& metadata,
+ aQuotaManager.LoadFullOriginMetadataWithRestore(directory));
+
+ mPersisted = metadata.mPersisted;
+ } else {
+ // The directory has not been created yet.
+ mPersisted = false;
+ }
+
+ return NS_OK;
+}
+
+void PersistedOp::GetResponse(RequestResponse& aResponse) {
+ AssertIsOnOwningThread();
+
+ PersistedResponse persistedResponse;
+ persistedResponse.persisted() = mPersisted;
+
+ aResponse = persistedResponse;
+}
+
+PersistOp::PersistOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const RequestParams& aParams)
+ : PersistRequestBase(std::move(aQuotaManager),
+ aParams.get_PersistParams().principalInfo()) {
+ MOZ_ASSERT(aParams.type() == RequestParams::TPersistParams);
+}
+
+nsresult PersistOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+ aQuotaManager.AssertStorageIsInitializedInternal();
+
+ const OriginMetadata originMetadata = {mPrincipalMetadata,
+ PERSISTENCE_TYPE_DEFAULT};
+
+ AUTO_PROFILER_LABEL("PersistOp::DoDirectoryWork", OTHER);
+
+ // Update directory metadata on disk first. Then, create/update the
+ // originInfo if needed.
+ QM_TRY_INSPECT(const auto& directory,
+ aQuotaManager.GetOriginDirectory(originMetadata));
+
+ QM_TRY_INSPECT(const bool& created,
+ aQuotaManager.EnsureOriginDirectory(*directory));
+
+ if (created) {
+ int64_t timestamp;
+
+ // Origin directory has been successfully created.
+ // Create OriginInfo too if temporary storage was already initialized.
+ if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
+ timestamp = aQuotaManager.NoteOriginDirectoryCreated(
+ originMetadata, /* aPersisted */ true);
+ } else {
+ timestamp = PR_Now();
+ }
+
+ QM_TRY(MOZ_TO_RESULT(QuotaManager::CreateDirectoryMetadata2(
+ *directory, timestamp,
+ /* aPersisted */ true, originMetadata)));
+ } else {
+ // Get the metadata (restore the metadata file if necessary). We only use
+ // the persisted flag.
+ QM_TRY_INSPECT(const auto& metadata,
+ aQuotaManager.LoadFullOriginMetadataWithRestore(directory));
+
+ if (!metadata.mPersisted) {
+ QM_TRY_INSPECT(const auto& file,
+ CloneFileAndAppend(
+ *directory, nsLiteralString(METADATA_V2_FILE_NAME)));
+
+ QM_TRY_INSPECT(const auto& stream,
+ GetBinaryOutputStream(*file, FileFlag::Update));
+
+ MOZ_ASSERT(stream);
+
+ // Update origin access time while we are here.
+ QM_TRY(MOZ_TO_RESULT(stream->Write64(PR_Now())));
+
+ // Set the persisted flag to true.
+ QM_TRY(MOZ_TO_RESULT(stream->WriteBoolean(true)));
+ }
+
+ // Directory metadata has been successfully updated.
+ // Update OriginInfo too if temporary storage was already initialized.
+ if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
+ aQuotaManager.PersistOrigin(originMetadata);
+ }
+ }
+
+ return NS_OK;
+}
+
+void PersistOp::GetResponse(RequestResponse& aResponse) {
+ AssertIsOnOwningThread();
+
+ aResponse = PersistResponse();
+}
+
+EstimateOp::EstimateOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
+ const EstimateParams& aParams)
+ : OpenStorageDirectoryHelper(std::move(aQuotaManager),
+ "dom::quota::EstimateOp"),
+ mParams(aParams) {
+ AssertIsOnOwningThread();
+}
+
+nsresult EstimateOp::DoInit(QuotaManager& aQuotaManager) {
+ AssertIsOnOwningThread();
+
+ QM_TRY_UNWRAP(
+ PrincipalMetadata principalMetadata,
+ aQuotaManager.GetInfoFromValidatedPrincipalInfo(mParams.principalInfo()));
+
+ principalMetadata.AssertInvariants();
+
+ mOriginMetadata = {std::move(principalMetadata), PERSISTENCE_TYPE_DEFAULT};
+
+ return NS_OK;
+}
+
+RefPtr<BoolPromise> EstimateOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ // XXX In theory, we should be locking entire group, not just one origin.
+ return OpenStorageDirectory(
+ Nullable<PersistenceType>(mOriginMetadata.mPersistenceType),
+ OriginScope::FromOrigin(mOriginMetadata.mOrigin),
+ Nullable<Client::Type>(),
+ /* aExclusive */ false);
+}
+
+nsresult EstimateOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+ aQuotaManager.AssertStorageIsInitializedInternal();
+
+ AUTO_PROFILER_LABEL("EstimateOp::DoDirectoryWork", OTHER);
+
+ // Ensure temporary storage is initialized. If temporary storage hasn't been
+ // initialized yet, the method will initialize it by traversing the
+ // repositories for temporary and default storage (including origins
+ // belonging to our group).
+ QM_TRY(MOZ_TO_RESULT(
+ aQuotaManager.EnsureTemporaryStorageIsInitializedInternal()));
+
+ // Get cached usage (the method doesn't have to stat any files).
+ mUsageAndLimit = aQuotaManager.GetUsageAndLimitForEstimate(mOriginMetadata);
+
+ return NS_OK;
+}
+
+void EstimateOp::GetResponse(RequestResponse& aResponse) {
+ AssertIsOnOwningThread();
+
+ EstimateResponse estimateResponse;
+
+ estimateResponse.usage() = mUsageAndLimit.first;
+ estimateResponse.limit() = mUsageAndLimit.second;
+
+ aResponse = estimateResponse;
+}
+
+void EstimateOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+ListOriginsOp::ListOriginsOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
+ : OpenStorageDirectoryHelper(std::move(aQuotaManager),
+ "dom::quota::ListOriginsOp") {
+ AssertIsOnOwningThread();
+}
+
+RefPtr<BoolPromise> ListOriginsOp::OpenDirectory() {
+ AssertIsOnOwningThread();
+
+ return OpenStorageDirectory(Nullable<PersistenceType>(),
+ OriginScope::FromNull(), Nullable<Client::Type>(),
+ /* aExclusive */ false);
+}
+
+nsresult ListOriginsOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
+ AssertIsOnIOThread();
+ aQuotaManager.AssertStorageIsInitializedInternal();
+
+ AUTO_PROFILER_LABEL("ListOriginsOp::DoDirectoryWork", OTHER);
+
+ for (const PersistenceType type : kAllPersistenceTypes) {
+ QM_TRY(MOZ_TO_RESULT(TraverseRepository(aQuotaManager, type)));
+ }
+
+ // TraverseRepository above only consulted the file-system to get a list of
+ // known origins, but we also need to include origins that have pending
+ // quota usage.
+
+ aQuotaManager.CollectPendingOriginsForListing([this](const auto& originInfo) {
+ mOrigins.AppendElement(originInfo->Origin());
+ });
+
+ return NS_OK;
+}
+
+const Atomic<bool>& ListOriginsOp::GetIsCanceledFlag() {
+ AssertIsOnIOThread();
+
+ return mCanceled;
+}
+
+nsresult ListOriginsOp::ProcessOrigin(QuotaManager& aQuotaManager,
+ nsIFile& aOriginDir,
+ const bool aPersistent,
+ const PersistenceType aPersistenceType) {
+ AssertIsOnIOThread();
+
+ QM_TRY_UNWRAP(auto maybeMetadata,
+ QM_OR_ELSE_WARN_IF(
+ // Expression
+ aQuotaManager.GetOriginMetadata(&aOriginDir)
+ .map([](auto metadata) -> Maybe<OriginMetadata> {
+ return Some(std::move(metadata));
+ }),
+ // Predicate.
+ IsSpecificError<NS_ERROR_MALFORMED_URI>,
+ // Fallback.
+ ErrToDefaultOk<Maybe<OriginMetadata>>));
+
+ if (!maybeMetadata) {
+ // Unknown directories during listing are allowed. Just warn if we find
+ // them.
+ QM_TRY_INSPECT(const auto& leafName,
+ MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, aOriginDir,
+ GetLeafName));
+
+ UNKNOWN_FILE_WARNING(leafName);
+ return NS_OK;
+ }
+
+ auto metadata = maybeMetadata.extract();
+
+ if (aQuotaManager.IsOriginInternal(metadata.mOrigin)) {
+ return NS_OK;
+ }
+
+ mOrigins.AppendElement(std::move(metadata.mOrigin));
+
+ return NS_OK;
+}
+
+void ListOriginsOp::GetResponse(RequestResponse& aResponse) {
+ AssertIsOnOwningThread();
+
+ aResponse = ListOriginsResponse();
+ if (mOrigins.IsEmpty()) {
+ return;
+ }
+
+ nsTArray<nsCString>& origins = aResponse.get_ListOriginsResponse().origins();
+ mOrigins.SwapElements(origins);
+}
+
+void ListOriginsOp::CloseDirectory() {
+ AssertIsOnOwningThread();
+
+ mDirectoryLock = nullptr;
+}
+
+} // namespace mozilla::dom::quota