/* -*- 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/DirectoryLockInlines.h"
#include "mozilla/dom/quota/OriginDirectoryLock.h"
#include "mozilla/dom/quota/PersistenceType.h"
#include "mozilla/dom/quota/PrincipalUtils.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/PersistenceScope.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/UniversalDirectoryLock.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 "OriginParser.h"
#include "QuotaRequestBase.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 PersistenceScope& aPersistenceScope,
const OriginScope& aOriginScope,
const Nullable<Client::Type>& aClientType,
bool aExclusive,
bool aInitializeOrigins =
false,
DirectoryLockCategory aCategory = DirectoryLockCategory::None);
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();
}
NS_INLINE_DECL_REFCOUNTING(FinalizeOriginEvictionOp, override)
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();
}
NS_INLINE_DECL_REFCOUNTING(SaveOriginAccessTimeOp, override)
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 UnwrapResolveValue() 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 UnwrapResolveValue() override {
return true; }
void CloseDirectory() override;
};
class CancelableHelper {
protected:
virtual const Atomic<
bool>& GetIsCanceledFlag() = 0;
};
// 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 CancelableHelper {
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 nsresult ProcessOrigin(QuotaManager& aQuotaManager,
nsIFile& aOriginDir,
const bool aPersistent,
const PersistenceType aPersistenceType) = 0;
};
class OriginUsageHelper :
public CancelableHelper {
protected:
mozilla::Result<UsageInfo, nsresult> GetUsageForOrigin(
QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
const OriginMetadata& aOriginMetadata);
private:
mozilla::Result<UsageInfo, nsresult> GetUsageForOriginEntries(
QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
const OriginMetadata& aOriginMetadata, nsIFile& aDirectory,
bool aInitialized);
};
class GetUsageOp final
:
public OpenStorageDirectoryHelper<
ResolvableNormalOriginOp<OriginUsageMetadataArray,
true>>,
public TraverseRepositoryHelper,
public OriginUsageHelper {
OriginUsageMetadataArray mOriginUsages;
nsTHashMap<nsCStringHashKey, uint32_t> mOriginUsagesIndex;
bool mGetAll;
public:
GetUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
bool aGetAll);
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;
const Atomic<
bool>& GetIsCanceledFlag() override;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
nsresult ProcessOrigin(QuotaManager& aQuotaManager, nsIFile& aOriginDir,
const bool aPersistent,
const PersistenceType aPersistenceType) override;
OriginUsageMetadataArray UnwrapResolveValue() override;
void CloseDirectory() override;
};
class GetOriginUsageOp final
:
public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<UsageInfo>>,
public OriginUsageHelper {
const PrincipalInfo mPrincipalInfo;
PrincipalMetadata mPrincipalMetadata;
UsageInfo mUsageInfo;
public:
GetOriginUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const PrincipalInfo& aPrincipalInfo);
private:
~GetOriginUsageOp() =
default;
nsresult DoInit(QuotaManager& aQuotaManager) override;
RefPtr<BoolPromise> OpenDirectory() override;
virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
const Atomic<
bool>& GetIsCanceledFlag() override;
UsageInfo UnwrapResolveValue() 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 UnwrapResolveValue() override;
};
class PersistentStorageInitializedOp final :
public InitializedRequestBase {
public:
explicit PersistentStorageInitializedOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
: InitializedRequestBase(std::move(aQuotaManager),
"dom::quota::PersistentStorageInitializedOp") {}
private:
~PersistentStorageInitializedOp() =
default;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
bool UnwrapResolveValue() override;
};
class TemporaryStorageInitializedOp final :
public InitializedRequestBase {
public:
explicit TemporaryStorageInitializedOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
: InitializedRequestBase(std::move(aQuotaManager),
"dom::quota::TemporaryStorageInitializedOp") {}
private:
~TemporaryStorageInitializedOp() =
default;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
bool UnwrapResolveValue() override;
};
class TemporaryGroupInitializedOp final
:
public ResolvableNormalOriginOp<
bool> {
const PrincipalMetadata mPrincipalMetadata;
bool mInitialized;
public:
explicit TemporaryGroupInitializedOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const PrincipalMetadata& aPrincipalMetadata);
private:
~TemporaryGroupInitializedOp() =
default;
RefPtr<BoolPromise> OpenDirectory() override;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
bool UnwrapResolveValue() override;
void CloseDirectory() override;
};
class InitializedOriginRequestBase :
public ResolvableNormalOriginOp<
bool> {
protected:
const PrincipalMetadata mPrincipalMetadata;
bool mInitialized;
InitializedOriginRequestBase(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const char* aName,
const PrincipalMetadata& aPrincipalMetadata);
private:
RefPtr<BoolPromise> OpenDirectory() override;
void CloseDirectory() override;
};
class PersistentOriginInitializedOp final
:
public InitializedOriginRequestBase {
public:
explicit PersistentOriginInitializedOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const OriginMetadata& aOriginMetadata);
private:
~PersistentOriginInitializedOp() =
default;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
bool UnwrapResolveValue() override;
};
class TemporaryOriginInitializedOp final :
public InitializedOriginRequestBase {
const PersistenceType mPersistenceType;
public:
explicit TemporaryOriginInitializedOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const OriginMetadata& aOriginMetadata);
private:
~TemporaryOriginInitializedOp() =
default;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
bool UnwrapResolveValue() 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 UnwrapResolveValue() override;
void CloseDirectory() override;
};
class InitializePersistentStorageOp final
:
public ResolvableNormalOriginOp<
bool> {
RefPtr<UniversalDirectoryLock> mDirectoryLock;
public:
InitializePersistentStorageOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
RefPtr<UniversalDirectoryLock> aDirectoryLock);
private:
~InitializePersistentStorageOp() =
default;
RefPtr<BoolPromise> OpenDirectory() override;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
bool UnwrapResolveValue() override;
void CloseDirectory() override;
};
class InitTemporaryStorageOp final
:
public ResolvableNormalOriginOp<MaybePrincipalMetadataArray,
true> {
MaybePrincipalMetadataArray mAllTemporaryGroups;
RefPtr<UniversalDirectoryLock> mDirectoryLock;
public:
InitTemporaryStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
RefPtr<UniversalDirectoryLock> aDirectoryLock);
private:
~InitTemporaryStorageOp() =
default;
RefPtr<BoolPromise> OpenDirectory() override;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
MaybePrincipalMetadataArray UnwrapResolveValue() override;
void CloseDirectory() override;
};
class InitializeTemporaryGroupOp final :
public ResolvableNormalOriginOp<
bool> {
const PrincipalMetadata mPrincipalMetadata;
RefPtr<UniversalDirectoryLock> mDirectoryLock;
public:
InitializeTemporaryGroupOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const PrincipalMetadata& aPrincipalMetadata,
RefPtr<UniversalDirectoryLock> aDirectoryLock);
private:
~InitializeTemporaryGroupOp() =
default;
RefPtr<BoolPromise> OpenDirectory() override;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
bool UnwrapResolveValue() override;
void CloseDirectory() override;
};
class InitializeOriginRequestBase :
public ResolvableNormalOriginOp<
bool> {
protected:
const PrincipalMetadata mPrincipalMetadata;
RefPtr<UniversalDirectoryLock> mDirectoryLock;
bool mCreated;
InitializeOriginRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const char* aName,
const PrincipalMetadata& aPrincipalMetadata,
RefPtr<UniversalDirectoryLock> aDirectoryLock);
private:
RefPtr<BoolPromise> OpenDirectory() override;
void CloseDirectory() override;
};
class InitializePersistentOriginOp final :
public InitializeOriginRequestBase {
public:
InitializePersistentOriginOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const OriginMetadata& aOriginMetadata,
RefPtr<UniversalDirectoryLock> aDirectoryLock);
private:
~InitializePersistentOriginOp() =
default;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
bool UnwrapResolveValue() override;
};
class InitializeTemporaryOriginOp final :
public InitializeOriginRequestBase {
const PersistenceType mPersistenceType;
const bool mCreateIfNonExistent;
public:
InitializeTemporaryOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const OriginMetadata& aOriginMetadata,
bool aCreateIfNonExistent,
RefPtr<UniversalDirectoryLock> aDirectoryLock);
private:
~InitializeTemporaryOriginOp() =
default;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
bool UnwrapResolveValue() 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 UnwrapResolveValue() 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 UnwrapResolveValue() 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 GetCachedOriginUsageOp
:
public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<uint64_t>> {
const PrincipalInfo mPrincipalInfo;
PrincipalMetadata mPrincipalMetadata;
uint64_t mUsage;
public:
GetCachedOriginUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const PrincipalInfo& aPrincipalInfo);
private:
~GetCachedOriginUsageOp() =
default;
nsresult DoInit(QuotaManager& aQuotaManager) override;
RefPtr<BoolPromise> OpenDirectory() override;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
uint64_t UnwrapResolveValue() override;
void CloseDirectory() override;
};
class ListCachedOriginsOp final
:
public OpenStorageDirectoryHelper<
ResolvableNormalOriginOp<CStringArray,
/* IsExclusive */ true>> {
nsTArray<nsCString> mOrigins;
public:
explicit ListCachedOriginsOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
private:
~ListCachedOriginsOp() =
default;
RefPtr<BoolPromise> OpenDirectory() override;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
CStringArray UnwrapResolveValue() 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 UnwrapResolveValue() override;
void CloseDirectory() override;
};
class ClearRequestBase
:
public OpenStorageDirectoryHelper<
ResolvableNormalOriginOp<OriginMetadataArray,
true>> {
Atomic<uint64_t> mIterations;
protected:
OriginMetadataArray mOriginMetadataArray;
ClearRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const char* aName)
: OpenStorageDirectoryHelper(std::move(aQuotaManager), aName),
mIterations(0) {
AssertIsOnOwningThread();
}
void DeleteFiles(QuotaManager& aQuotaManager,
const OriginMetadata& aOriginMetadata);
void DeleteFiles(QuotaManager& aQuotaManager,
PersistenceType aPersistenceType,
const OriginScope& aOriginScope);
private:
template <
typename FileCollector>
void DeleteFilesInternal(QuotaManager& aQuotaManager,
PersistenceType aPersistenceType,
const OriginScope& aOriginScope,
const FileCollector& aFileCollector);
void DoStringify(nsACString& aData) override {
aData.Append(
"ClearRequestBase "_ns +
//
kStringifyStartInstance +
//
"Iterations:"_ns +
IntToCString(
static_cast<uint64_t>(mIterations)) +
//
kStringifyEndInstance);
}
};
class ClearOriginOp final :
public ClearRequestBase {
const PrincipalInfo mPrincipalInfo;
PrincipalMetadata mPrincipalMetadata;
const PersistenceScope mPersistenceScope;
public:
ClearOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const mozilla::Maybe<PersistenceType>& aPersistenceType,
const PrincipalInfo& aPrincipalInfo);
private:
~ClearOriginOp() =
default;
nsresult DoInit(QuotaManager& aQuotaManager) override;
RefPtr<BoolPromise> OpenDirectory() override;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
OriginMetadataArray UnwrapResolveValue() override;
void CloseDirectory() override;
};
class ClearClientOp final
:
public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<
bool>> {
const PrincipalInfo mPrincipalInfo;
PrincipalMetadata mPrincipalMetadata;
const PersistenceScope mPersistenceScope;
const Client::Type mClientType;
public:
ClearClientOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
mozilla::Maybe<PersistenceType> aPersistenceType,
const PrincipalInfo& aPrincipalInfo,
const Client::Type aClientType);
private:
~ClearClientOp() =
default;
nsresult DoInit(QuotaManager& aQuotaManager) override;
RefPtr<BoolPromise> OpenDirectory() override;
void DeleteFiles(
const ClientMetadata& aClientMetadata);
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
bool UnwrapResolveValue() override;
void CloseDirectory() override;
};
class ClearStoragesForOriginPrefixOp final
:
public OpenStorageDirectoryHelper<ClearRequestBase> {
const PrincipalInfo mPrincipalInfo;
PrincipalMetadata mPrincipalMetadata;
const PersistenceScope mPersistenceScope;
public:
ClearStoragesForOriginPrefixOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const Maybe<PersistenceType>& aPersistenceType,
const PrincipalInfo& aPrincipalInfo);
private:
~ClearStoragesForOriginPrefixOp() =
default;
nsresult DoInit(QuotaManager& aQuotaManager) override;
RefPtr<BoolPromise> OpenDirectory() override;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
OriginMetadataArray UnwrapResolveValue() 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;
OriginMetadataArray UnwrapResolveValue() override;
void CloseDirectory() override;
};
class ShutdownOriginOp final
:
public ResolvableNormalOriginOp<OriginMetadataArray,
true> {
const PrincipalInfo mPrincipalInfo;
PrincipalMetadata mPrincipalMetadata;
OriginMetadataArray mOriginMetadataArray;
RefPtr<UniversalDirectoryLock> mDirectoryLock;
const PersistenceScope mPersistenceScope;
public:
ShutdownOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
mozilla::Maybe<PersistenceType> aPersistenceType,
const PrincipalInfo& aPrincipalInfo);
private:
~ShutdownOriginOp() =
default;
nsresult DoInit(QuotaManager& aQuotaManager) override;
RefPtr<BoolPromise> OpenDirectory() override;
void CollectOriginMetadata(
const OriginMetadata& aOriginMetadata);
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
OriginMetadataArray UnwrapResolveValue() override;
void CloseDirectory() override;
};
class ShutdownClientOp final :
public ResolvableNormalOriginOp<
bool> {
const PrincipalInfo mPrincipalInfo;
PrincipalMetadata mPrincipalMetadata;
RefPtr<UniversalDirectoryLock> mDirectoryLock;
const PersistenceScope mPersistenceScope;
const Client::Type mClientType;
public:
ShutdownClientOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
mozilla::Maybe<PersistenceType> aPersistenceType,
const PrincipalInfo& aPrincipalInfo,
const Client::Type aClientType);
private:
~ShutdownClientOp() =
default;
nsresult DoInit(QuotaManager& aQuotaManager) override;
RefPtr<BoolPromise> OpenDirectory() override;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
bool UnwrapResolveValue() 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<
ResolvableNormalOriginOp<CStringArray,
/* IsExclusive */ true>>,
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;
CStringArray UnwrapResolveValue() 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<ResolvableNormalOriginOp<OriginUsageMetadataArray,
true>>
CreateGetUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
bool aGetAll) {
return MakeRefPtr<GetUsageOp>(std::move(aQuotaManager), aGetAll);
}
RefPtr<ResolvableNormalOriginOp<UsageInfo>> CreateGetOriginUsageOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
return MakeRefPtr<GetOriginUsageOp>(std::move(aQuotaManager), aPrincipalInfo);
}
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>> CreatePersistentStorageInitializedOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
return MakeRefPtr<PersistentStorageInitializedOp>(std::move(aQuotaManager));
}
RefPtr<ResolvableNormalOriginOp<
bool>> CreateTemporaryStorageInitializedOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
return MakeRefPtr<TemporaryStorageInitializedOp>(std::move(aQuotaManager));
}
RefPtr<ResolvableNormalOriginOp<
bool>> CreateTemporaryGroupInitializedOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const PrincipalMetadata& aPrincipalMetadata) {
return MakeRefPtr<TemporaryGroupInitializedOp>(std::move(aQuotaManager),
aPrincipalMetadata);
}
RefPtr<ResolvableNormalOriginOp<
bool>> CreatePersistentOriginInitializedOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const OriginMetadata& aOriginMetadata) {
return MakeRefPtr<PersistentOriginInitializedOp>(std::move(aQuotaManager),
aOriginMetadata);
}
RefPtr<ResolvableNormalOriginOp<
bool>> CreateTemporaryOriginInitializedOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const OriginMetadata& aOriginMetadata) {
return MakeRefPtr<TemporaryOriginInitializedOp>(std::move(aQuotaManager),
aOriginMetadata);
}
RefPtr<ResolvableNormalOriginOp<
bool>> CreateInitOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
RefPtr<UniversalDirectoryLock> aDirectoryLock) {
return MakeRefPtr<InitOp>(std::move(aQuotaManager),
std::move(aDirectoryLock));
}
RefPtr<ResolvableNormalOriginOp<
bool>> CreateInitializePersistentStorageOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
RefPtr<UniversalDirectoryLock> aDirectoryLock) {
return MakeRefPtr<InitializePersistentStorageOp>(std::move(aQuotaManager),
std::move(aDirectoryLock));
}
RefPtr<ResolvableNormalOriginOp<MaybePrincipalMetadataArray,
true>>
CreateInitTemporaryStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
RefPtr<UniversalDirectoryLock> aDirectoryLock) {
return MakeRefPtr<InitTemporaryStorageOp>(std::move(aQuotaManager),
std::move(aDirectoryLock));
}
RefPtr<ResolvableNormalOriginOp<
bool>> CreateInitializeTemporaryGroupOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const PrincipalMetadata& aPrincipalMetadata,
RefPtr<UniversalDirectoryLock> aDirectoryLock) {
return MakeRefPtr<InitializeTemporaryGroupOp>(
std::move(aQuotaManager), aPrincipalMetadata, std::move(aDirectoryLock));
}
RefPtr<ResolvableNormalOriginOp<
bool>> CreateInitializePersistentOriginOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const OriginMetadata& aOriginMetadata,
RefPtr<UniversalDirectoryLock> aDirectoryLock) {
return MakeRefPtr<InitializePersistentOriginOp>(
std::move(aQuotaManager), aOriginMetadata, std::move(aDirectoryLock));
}
RefPtr<ResolvableNormalOriginOp<
bool>> CreateInitializeTemporaryOriginOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const OriginMetadata& aOriginMetadata,
bool aCreateIfNonExistent,
RefPtr<UniversalDirectoryLock> aDirectoryLock) {
return MakeRefPtr<InitializeTemporaryOriginOp>(
std::move(aQuotaManager), aOriginMetadata, aCreateIfNonExistent,
std::move(aDirectoryLock));
}
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<uint64_t>> CreateGetCachedOriginUsageOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
return MakeRefPtr<GetCachedOriginUsageOp>(std::move(aQuotaManager),
aPrincipalInfo);
}
RefPtr<ResolvableNormalOriginOp<CStringArray,
true>> CreateListCachedOriginsOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
return MakeRefPtr<ListCachedOriginsOp>(std::move(aQuotaManager));
}
RefPtr<ResolvableNormalOriginOp<
bool>> CreateClearStorageOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
return MakeRefPtr<ClearStorageOp>(std::move(aQuotaManager));
}
RefPtr<ResolvableNormalOriginOp<OriginMetadataArray,
true>> CreateClearOriginOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const Maybe<PersistenceType>& aPersistenceType,
const PrincipalInfo& aPrincipalInfo) {
return MakeRefPtr<ClearOriginOp>(std::move(aQuotaManager), aPersistenceType,
aPrincipalInfo);
}
RefPtr<ResolvableNormalOriginOp<
bool>> CreateClearClientOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
Maybe<PersistenceType> aPersistenceType,
const PrincipalInfo& aPrincipalInfo, Client::Type aClientType) {
return MakeRefPtr<ClearClientOp>(std::move(aQuotaManager), aPersistenceType,
aPrincipalInfo, aClientType);
}
RefPtr<ResolvableNormalOriginOp<OriginMetadataArray,
true>>
CreateClearStoragesForOriginPrefixOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const Maybe<PersistenceType>& aPersistenceType,
const PrincipalInfo& aPrincipalInfo) {
return MakeRefPtr<ClearStoragesForOriginPrefixOp>(
std::move(aQuotaManager), aPersistenceType, aPrincipalInfo);
}
RefPtr<ResolvableNormalOriginOp<OriginMetadataArray,
true>> CreateClearDataOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const OriginAttributesPattern& aPattern) {
return MakeRefPtr<ClearDataOp>(std::move(aQuotaManager), aPattern);
}
RefPtr<ResolvableNormalOriginOp<OriginMetadataArray,
true>>
CreateShutdownOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
Maybe<PersistenceType> aPersistenceType,
const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
return MakeRefPtr<ShutdownOriginOp>(std::move(aQuotaManager),
aPersistenceType, aPrincipalInfo);
}
RefPtr<ResolvableNormalOriginOp<
bool>> CreateShutdownClientOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
Maybe<PersistenceType> aPersistenceType,
const PrincipalInfo& aPrincipalInfo, Client::Type aClientType) {
return MakeRefPtr<ShutdownClientOp>(
std::move(aQuotaManager), aPersistenceType, aPrincipalInfo, aClientType);
}
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<ResolvableNormalOriginOp<CStringArray,
/* IsExclusive */ true>>
CreateListOriginsOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
return MakeRefPtr<ListOriginsOp>(std::move(aQuotaManager));
}
template <
class Base>
RefPtr<BoolPromise> OpenStorageDirectoryHelper<Base>::OpenStorageDirectory(
const PersistenceScope& aPersistenceScope,
const OriginScope& aOriginScope,
const Nullable<Client::Type>& aClientType,
bool aExclusive,
bool aInitializeOrigins,
const DirectoryLockCategory aCategory) {
return Base::mQuotaManager
->OpenStorageDirectory(aPersistenceScope, aOriginScope, aClientType,
aExclusive, aInitializeOrigins, aCategory)
->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->OriginMetadata(),
Nullable<Client::Type>());
}
return NS_OK;
}
void FinalizeOriginEvictionOp::UnblockOpen() {
AssertIsOnOwningThread();
nsTArray<OriginMetadata> origins;
std::transform(mLocks.cbegin(), mLocks.cend(), MakeBackInserter(origins),
[](
const auto& lock) {
return lock->OriginMetadata(); });
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NS_NewRunnableFunction(
"dom::quota::FinalizeOriginEvictionOp::UnblockOpen",
[quotaManager = mQuotaManager, origins = std::move(origins)]() {
quotaManager->NoteUninitializedOrigins(origins);
})));
for (
const auto& lock : mLocks) {
lock->Drop();
}
mLocks.Clear();
}
RefPtr<BoolPromise> SaveOriginAccessTimeOp::OpenDirectory() {
AssertIsOnOwningThread();
return OpenStorageDirectory(
PersistenceScope::CreateFromValue(mOriginMetadata.mPersistenceType),
OriginScope::FromOrigin(mOriginMetadata), 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() {}
void SaveOriginAccessTimeOp::CloseDirectory() {
AssertIsOnOwningThread();
SafeDropDirectoryLock(mDirectoryLock);
}
RefPtr<BoolPromise> ClearPrivateRepositoryOp::OpenDirectory() {
AssertIsOnOwningThread();
return OpenStorageDirectory(
PersistenceScope::CreateFromValue(PERSISTENCE_TYPE_PRIVATE),
OriginScope::FromNull(), Nullable<Client::Type>(),
/* aExclusive */ true, /* aInitializeOrigins */ false,
DirectoryLockCategory::UninitOrigins);
}
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();
SafeDropDirectoryLock(mDirectoryLock);
}
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(
PersistenceScope::CreateFromNull(), OriginScope::FromNull(),
Nullable<Client::Type>(),
/* aExclusive */ true, DirectoryLockCategory::UninitStorage);
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();
DropDirectoryLockIfNotDropped(mDirectoryLock);
}
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;
}
Result<UsageInfo, nsresult> OriginUsageHelper::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 || GetIsCanceledFlag()) {
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.IsPersistentOriginInitializedInternal(
aOriginMetadata.mOrigin);
}
else {
initialized = aQuotaManager.IsTemporaryStorageInitializedInternal();
}
return GetUsageForOriginEntries(aQuotaManager, aPersistenceType,
aOriginMetadata, *directory, initialized);
}
Result<UsageInfo, nsresult> OriginUsageHelper::GetUsageForOriginEntries(
QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
const OriginMetadata& aOriginMetadata, nsIFile& aDirectory,
const bool aInitialized) {
AssertIsOnIOThread();
QM_TRY_RETURN((ReduceEachFileAtomicCancelable(
aDirectory, GetIsCanceledFlag(), UsageInfo{},
[&](UsageInfo oldUsageInfo,
const nsCOMPtr<nsIFile>& file)
-> mozilla::Result<UsageInfo, nsresult> {
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,
GetIsCanceledFlag())
: client->InitOrigin(
aPersistenceType, aOriginMetadata,
GetIsCanceledFlag()));
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;
})));
}
GetUsageOp::GetUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
bool aGetAll)
: OpenStorageDirectoryHelper(std::move(aQuotaManager),
"dom::quota::GetUsageOp"),
mGetAll(aGetAll) {
AssertIsOnOwningThread();
}
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());
OriginUsageMetadata metadata;
metadata.mOrigin = aOrigin;
metadata.mPersistenceType = PERSISTENCE_TYPE_DEFAULT;
metadata.mPersisted =
false;
metadata.mLastAccessTime = 0;
metadata.mUsage = 0;
return mOriginUsages.EmplaceBack(std::move(metadata));
});
if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) {
originUsage->mPersisted = aPersisted;
}
originUsage->mUsage = originUsage->mUsage + aUsage;
originUsage->mLastAccessTime =
std::max<int64_t>(originUsage->mLastAccessTime, aTimestamp);
}
const Atomic<
bool>& GetUsageOp::GetIsCanceledFlag() {
AssertIsOnIOThread();
return Canceled();
}
// 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(PersistenceScope::CreateFromNull(),
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;
}
OriginUsageMetadataArray GetUsageOp::UnwrapResolveValue() {
AssertIsOnOwningThread();
return std::move(mOriginUsages);
}
void GetUsageOp::CloseDirectory() {
AssertIsOnOwningThread();
SafeDropDirectoryLock(mDirectoryLock);
}
GetOriginUsageOp::GetOriginUsageOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const PrincipalInfo& aPrincipalInfo)
: OpenStorageDirectoryHelper(std::move(aQuotaManager),
"dom::quota::GetOriginUsageOp"),
mPrincipalInfo(aPrincipalInfo) {
AssertIsOnOwningThread();
}
nsresult GetOriginUsageOp::DoInit(QuotaManager& aQuotaManager) {
AssertIsOnOwningThread();
QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
aQuotaManager, mPrincipalInfo));
mPrincipalMetadata.AssertInvariants();
return NS_OK;
}
RefPtr<BoolPromise> GetOriginUsageOp::OpenDirectory() {
AssertIsOnOwningThread();
return OpenStorageDirectory(PersistenceScope::CreateFromNull(),
OriginScope::FromOrigin(mPrincipalMetadata),
Nullable<Client::Type>(),
/* aExclusive */ false);
}
const Atomic<
bool>& GetOriginUsageOp::GetIsCanceledFlag() {
AssertIsOnIOThread();
return Canceled();
}
nsresult GetOriginUsageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
AssertIsOnIOThread();
aQuotaManager.AssertStorageIsInitializedInternal();
MOZ_ASSERT(mUsageInfo.TotalUsage().isNothing());
AUTO_PROFILER_LABEL(
"GetOriginUsageOp::DoDirectoryWork", OTHER);
// Add all the persistent/temporary/default/private 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;
}
UsageInfo GetOriginUsageOp::UnwrapResolveValue() {
AssertIsOnOwningThread();
return mUsageInfo;
}
void GetOriginUsageOp::CloseDirectory() {
AssertIsOnOwningThread();
SafeDropDirectoryLock(mDirectoryLock);
}
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::UnwrapResolveValue() {
AssertIsOnOwningThread();
return mInitialized;
}
nsresult PersistentStorageInitializedOp::DoDirectoryWork(
QuotaManager& aQuotaManager) {
AssertIsOnIOThread();
AUTO_PROFILER_LABEL(
"PersistentStorageInitializedOp::DoDirectoryWork", OTHER);
mInitialized = aQuotaManager.IsPersistentStorageInitializedInternal();
return NS_OK;
}
bool PersistentStorageInitializedOp::UnwrapResolveValue() {
AssertIsOnOwningThread();
return mInitialized;
}
nsresult TemporaryStorageInitializedOp::DoDirectoryWork(
QuotaManager& aQuotaManager) {
AssertIsOnIOThread();
AUTO_PROFILER_LABEL(
"TemporaryStorageInitializedOp::DoDirectoryWork", OTHER);
mInitialized = aQuotaManager.IsTemporaryStorageInitializedInternal();
return NS_OK;
}
bool TemporaryStorageInitializedOp::UnwrapResolveValue() {
AssertIsOnOwningThread();
return mInitialized;
}
TemporaryGroupInitializedOp::TemporaryGroupInitializedOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const PrincipalMetadata& aPrincipalMetadata)
: ResolvableNormalOriginOp(std::move(aQuotaManager),
"dom::quota::TemporaryGroupInitializedOp"),
mPrincipalMetadata(aPrincipalMetadata),
mInitialized(
false) {
AssertIsOnOwningThread();
}
RefPtr<BoolPromise> TemporaryGroupInitializedOp::OpenDirectory() {
AssertIsOnOwningThread();
return BoolPromise::CreateAndResolve(
true, __func__);
}
nsresult TemporaryGroupInitializedOp::DoDirectoryWork(
QuotaManager& aQuotaManager) {
AssertIsOnIOThread();
AUTO_PROFILER_LABEL(
"TemporaryGroupInitializedOp::DoDirectoryWork", OTHER);
mInitialized =
aQuotaManager.IsTemporaryGroupInitializedInternal(mPrincipalMetadata);
return NS_OK;
}
bool TemporaryGroupInitializedOp::UnwrapResolveValue() {
AssertIsOnOwningThread();
return mInitialized;
}
void TemporaryGroupInitializedOp::CloseDirectory() { AssertIsOnOwningThread(); }
InitializedOriginRequestBase::InitializedOriginRequestBase(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const char* aName,
const PrincipalMetadata& aPrincipalMetadata)
: ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
mPrincipalMetadata(aPrincipalMetadata),
mInitialized(
false) {
AssertIsOnOwningThread();
}
RefPtr<BoolPromise> InitializedOriginRequestBase::OpenDirectory() {
AssertIsOnOwningThread();
return BoolPromise::CreateAndResolve(
true, __func__);
}
void InitializedOriginRequestBase::CloseDirectory() {
AssertIsOnOwningThread();
}
PersistentOriginInitializedOp::PersistentOriginInitializedOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const OriginMetadata& aOriginMetadata)
: InitializedOriginRequestBase(std::move(aQuotaManager),
"dom::quota::PersistentOriginInitializedOp",
aOriginMetadata) {
AssertIsOnOwningThread();
MOZ_ASSERT(aOriginMetadata.mPersistenceType == PERSISTENCE_TYPE_PERSISTENT);
}
nsresult PersistentOriginInitializedOp::DoDirectoryWork(
QuotaManager& aQuotaManager) {
AssertIsOnIOThread();
AUTO_PROFILER_LABEL(
"PersistentOriginInitializedOp::DoDirectoryWork", OTHER);
mInitialized = aQuotaManager.IsPersistentOriginInitializedInternal(
OriginMetadata{mPrincipalMetadata, PERSISTENCE_TYPE_PERSISTENT});
return NS_OK;
}
bool PersistentOriginInitializedOp::UnwrapResolveValue() {
AssertIsOnOwningThread();
return mInitialized;
}
TemporaryOriginInitializedOp::TemporaryOriginInitializedOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const OriginMetadata& aOriginMetadata)
: InitializedOriginRequestBase(std::move(aQuotaManager),
"dom::quota::TemporaryOriginInitializedOp",
aOriginMetadata),
mPersistenceType(aOriginMetadata.mPersistenceType) {
AssertIsOnOwningThread();
MOZ_ASSERT(aOriginMetadata.mPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
}
nsresult TemporaryOriginInitializedOp::DoDirectoryWork(
QuotaManager& aQuotaManager) {
AssertIsOnIOThread();
AUTO_PROFILER_LABEL(
"TemporaryOriginInitializedOp::DoDirectoryWork", OTHER);
mInitialized = aQuotaManager.IsTemporaryOriginInitializedInternal(
OriginMetadata{mPrincipalMetadata, mPersistenceType});
return NS_OK;
}
bool TemporaryOriginInitializedOp::UnwrapResolveValue() {
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();
--> --------------------
--> maximum size reached
--> --------------------