Source code
Revision control
Copy as Markdown
Other Tools
/* -*- 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,
#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/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/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/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 "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,
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 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;
};
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 GetResolveValue() 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 GetResolveValue() 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 ResolvableNormalOriginOp<bool> {
protected:
const PrincipalInfo mPrincipalInfo;
PrincipalMetadata mPrincipalMetadata;
RefPtr<UniversalDirectoryLock> mDirectoryLock;
bool mCreated;
InitializeOriginRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const char* aName,
const PrincipalInfo& aPrincipalInfo,
RefPtr<UniversalDirectoryLock> aDirectoryLock);
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 PrincipalInfo& aPrincipalInfo,
RefPtr<UniversalDirectoryLock> aDirectoryLock);
private:
~InitializePersistentOriginOp() = default;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
bool GetResolveValue() override;
};
class InitializeTemporaryOriginOp final : public InitializeOriginRequestBase {
const PersistenceType mPersistenceType;
public:
InitializeTemporaryOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
PersistenceType aPersistenceType,
const PrincipalInfo& aPrincipalInfo,
RefPtr<UniversalDirectoryLock> aDirectoryLock);
private:
~InitializeTemporaryOriginOp() = default;
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
bool GetResolveValue() 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 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 GetResolveValue() 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>> {
Atomic<uint64_t> mIterations;
protected:
ClearRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const char* aName)
: OpenStorageDirectoryHelper(std::move(aQuotaManager), aName),
mIterations(0) {
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);
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;
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 PersistenceScope mPersistenceScope;
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;
PersistenceScope mPersistenceScope;
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 {
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<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>> 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<ResolvableNormalOriginOp<bool>> CreateInitializePersistentOriginOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
RefPtr<UniversalDirectoryLock> aDirectoryLock) {
return MakeRefPtr<InitializePersistentOriginOp>(
std::move(aQuotaManager), aPrincipalInfo, std::move(aDirectoryLock));
}
RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializeTemporaryOriginOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
RefPtr<UniversalDirectoryLock> aDirectoryLock) {
return MakeRefPtr<InitializeTemporaryOriginOp>(
std::move(aQuotaManager), aPersistenceType, aPrincipalInfo,
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<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 PersistenceScope& aPersistenceScope, const OriginScope& aOriginScope,
const Nullable<Client::Type>& aClientType, bool aExclusive,
const DirectoryLockCategory aCategory) {
return Base::mQuotaManager
->OpenStorageDirectory(aPersistenceScope, aOriginScope, aClientType,
aExclusive, 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->GetPersistenceType(), lock->Origin(), Nullable<Client::Type>());
}
return NS_OK;
}
void FinalizeOriginEvictionOp::UnblockOpen() {
AssertIsOnOwningThread();
for (const auto& lock : mLocks) {
lock->Drop();
}
mLocks.Clear();
}
RefPtr<BoolPromise> SaveOriginAccessTimeOp::OpenDirectory() {
AssertIsOnOwningThread();
return OpenStorageDirectory(
PersistenceScope::CreateFromValue(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() {}
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);
}
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));