LSNG already uses some QuotaManager APIs to achieve that origin directories are not created if they don't exist during datastore preparation, but the feature is not easy to use and it's also not generalized enough for use in other quota clients. Besides that, the way how it's currently done in LSNG complicates removal of QuotaManager::EnsureTemporaryOriginIsInitializedInternal calls from LSNG. This patch is about generalizing of the feature, making it available to all quota clients. Differential Revision: https://phabricator.services.mozilla.com/D195551
3443 lines
108 KiB
C++
3443 lines
108 KiB
C++
/* -*- 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/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,
|
|
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 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 InitializedOriginRequestBase : public ResolvableNormalOriginOp<bool> {
|
|
protected:
|
|
const PrincipalInfo mPrincipalInfo;
|
|
PrincipalMetadata mPrincipalMetadata;
|
|
bool mInitialized;
|
|
|
|
InitializedOriginRequestBase(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
|
|
const PrincipalInfo& aPrincipalInfo);
|
|
|
|
private:
|
|
nsresult DoInit(QuotaManager& aQuotaManager) override;
|
|
|
|
RefPtr<BoolPromise> OpenDirectory() override;
|
|
|
|
void CloseDirectory() override;
|
|
};
|
|
|
|
class PersistentOriginInitializedOp final
|
|
: public InitializedOriginRequestBase {
|
|
public:
|
|
explicit PersistentOriginInitializedOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const PrincipalInfo& aPrincipalInfo);
|
|
|
|
private:
|
|
~PersistentOriginInitializedOp() = default;
|
|
|
|
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
|
|
|
|
bool GetResolveValue() override;
|
|
};
|
|
|
|
class TemporaryOriginInitializedOp final : public InitializedOriginRequestBase {
|
|
const PersistenceType mPersistenceType;
|
|
|
|
public:
|
|
explicit TemporaryOriginInitializedOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo);
|
|
|
|
private:
|
|
~TemporaryOriginInitializedOp() = 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;
|
|
const bool mCreateIfNonExistent;
|
|
|
|
public:
|
|
InitializeTemporaryOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
PersistenceType aPersistenceType,
|
|
const PrincipalInfo& aPrincipalInfo,
|
|
bool aCreateIfNonExistent,
|
|
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<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 GetResolveValue() 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 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;
|
|
|
|
OriginMetadataArray 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;
|
|
|
|
OriginMetadataArray GetResolveValue() 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 GetResolveValue() 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 GetResolveValue() override;
|
|
|
|
void CloseDirectory() override;
|
|
};
|
|
|
|
class PersistRequestBase : public OpenStorageDirectoryHelper<QuotaRequestBase> {
|
|
const PrincipalInfo mPrincipalInfo;
|
|
|
|
protected:
|
|
PrincipalMetadata mPrincipalMetadata;
|
|
|
|
protected:
|
|
PersistRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const PrincipalInfo& aPrincipalInfo);
|
|
|
|
nsresult DoInit(QuotaManager& aQuotaManager) override;
|
|
|
|
private:
|
|
RefPtr<BoolPromise> OpenDirectory() override;
|
|
|
|
void CloseDirectory() override;
|
|
};
|
|
|
|
class PersistedOp final : public PersistRequestBase {
|
|
bool mPersisted;
|
|
|
|
public:
|
|
PersistedOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const RequestParams& aParams);
|
|
|
|
private:
|
|
~PersistedOp() = default;
|
|
|
|
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
|
|
|
|
void GetResponse(RequestResponse& aResponse) override;
|
|
};
|
|
|
|
class PersistOp final : public PersistRequestBase {
|
|
public:
|
|
PersistOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const RequestParams& aParams);
|
|
|
|
private:
|
|
~PersistOp() = default;
|
|
|
|
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
|
|
|
|
void GetResponse(RequestResponse& aResponse) override;
|
|
};
|
|
|
|
class EstimateOp final : public OpenStorageDirectoryHelper<QuotaRequestBase> {
|
|
const EstimateParams mParams;
|
|
OriginMetadata mOriginMetadata;
|
|
std::pair<uint64_t, uint64_t> mUsageAndLimit;
|
|
|
|
public:
|
|
EstimateOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const EstimateParams& aParams);
|
|
|
|
private:
|
|
~EstimateOp() = default;
|
|
|
|
nsresult DoInit(QuotaManager& aQuotaManager) override;
|
|
|
|
RefPtr<BoolPromise> OpenDirectory() override;
|
|
|
|
virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
|
|
|
|
void GetResponse(RequestResponse& aResponse) override;
|
|
|
|
void CloseDirectory() override;
|
|
};
|
|
|
|
class ListOriginsOp final : public OpenStorageDirectoryHelper<QuotaRequestBase>,
|
|
public TraverseRepositoryHelper {
|
|
// XXX Bug 1521541 will make each origin has it's own state.
|
|
nsTArray<nsCString> mOrigins;
|
|
|
|
public:
|
|
explicit ListOriginsOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
|
|
|
|
private:
|
|
~ListOriginsOp() = default;
|
|
|
|
RefPtr<BoolPromise> OpenDirectory() override;
|
|
|
|
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
|
|
|
|
const Atomic<bool>& GetIsCanceledFlag() override;
|
|
|
|
nsresult ProcessOrigin(QuotaManager& aQuotaManager, nsIFile& aOriginDir,
|
|
const bool aPersistent,
|
|
const PersistenceType aPersistenceType) override;
|
|
|
|
void GetResponse(RequestResponse& aResponse) override;
|
|
|
|
void CloseDirectory() override;
|
|
};
|
|
|
|
RefPtr<OriginOperationBase> CreateFinalizeOriginEvictionOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
nsTArray<RefPtr<OriginDirectoryLock>>&& aLocks) {
|
|
return MakeRefPtr<FinalizeOriginEvictionOp>(std::move(aQuotaManager),
|
|
std::move(aLocks));
|
|
}
|
|
|
|
RefPtr<NormalOriginOperationBase> CreateSaveOriginAccessTimeOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const OriginMetadata& aOriginMetadata, int64_t aTimestamp) {
|
|
return MakeRefPtr<SaveOriginAccessTimeOp>(std::move(aQuotaManager),
|
|
aOriginMetadata, aTimestamp);
|
|
}
|
|
|
|
RefPtr<ResolvableNormalOriginOp<bool>> CreateClearPrivateRepositoryOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
|
|
return MakeRefPtr<ClearPrivateRepositoryOp>(std::move(aQuotaManager));
|
|
}
|
|
|
|
RefPtr<ResolvableNormalOriginOp<bool>> CreateShutdownStorageOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
|
|
return MakeRefPtr<ShutdownStorageOp>(std::move(aQuotaManager));
|
|
}
|
|
|
|
RefPtr<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>> CreatePersistentOriginInitializedOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
|
|
return MakeRefPtr<PersistentOriginInitializedOp>(std::move(aQuotaManager),
|
|
aPrincipalInfo);
|
|
}
|
|
|
|
RefPtr<ResolvableNormalOriginOp<bool>> CreateTemporaryOriginInitializedOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const PersistenceType aPersistenceType,
|
|
const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
|
|
return MakeRefPtr<TemporaryOriginInitializedOp>(
|
|
std::move(aQuotaManager), aPersistenceType, aPrincipalInfo);
|
|
}
|
|
|
|
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,
|
|
bool aCreateIfNonExistent, RefPtr<UniversalDirectoryLock> aDirectoryLock) {
|
|
return MakeRefPtr<InitializeTemporaryOriginOp>(
|
|
std::move(aQuotaManager), aPersistenceType, aPrincipalInfo,
|
|
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<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<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,
|
|
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->GetPersistenceType(), lock->Origin(), 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.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, /* 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::GetResolveValue() {
|
|
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,
|
|
aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
|
|
|
|
mPrincipalMetadata.AssertInvariants();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<BoolPromise> GetOriginUsageOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return OpenStorageDirectory(
|
|
PersistenceScope::CreateFromNull(),
|
|
OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
|
|
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::GetResolveValue() {
|
|
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::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return mInitialized;
|
|
}
|
|
|
|
nsresult TemporaryStorageInitializedOp::DoDirectoryWork(
|
|
QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
AUTO_PROFILER_LABEL("TemporaryStorageInitializedOp::DoDirectoryWork", OTHER);
|
|
|
|
mInitialized = aQuotaManager.IsTemporaryStorageInitializedInternal();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool TemporaryStorageInitializedOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return mInitialized;
|
|
}
|
|
|
|
InitializedOriginRequestBase::InitializedOriginRequestBase(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
|
|
const PrincipalInfo& aPrincipalInfo)
|
|
: ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
|
|
mPrincipalInfo(aPrincipalInfo),
|
|
mInitialized(false) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult InitializedOriginRequestBase::DoInit(QuotaManager& aQuotaManager) {
|
|
AssertIsOnOwningThread();
|
|
|
|
QM_TRY_UNWRAP(
|
|
mPrincipalMetadata,
|
|
aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
|
|
|
|
mPrincipalMetadata.AssertInvariants();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<BoolPromise> InitializedOriginRequestBase::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return BoolPromise::CreateAndResolve(true, __func__);
|
|
}
|
|
|
|
void InitializedOriginRequestBase::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
PersistentOriginInitializedOp::PersistentOriginInitializedOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const PrincipalInfo& aPrincipalInfo)
|
|
: InitializedOriginRequestBase(std::move(aQuotaManager),
|
|
"dom::quota::PersistentOriginInitializedOp",
|
|
aPrincipalInfo) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
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::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return mInitialized;
|
|
}
|
|
|
|
TemporaryOriginInitializedOp::TemporaryOriginInitializedOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo)
|
|
: InitializedOriginRequestBase(std::move(aQuotaManager),
|
|
"dom::quota::TemporaryOriginInitializedOp",
|
|
aPrincipalInfo),
|
|
mPersistenceType(aPersistenceType) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult TemporaryOriginInitializedOp::DoDirectoryWork(
|
|
QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
AUTO_PROFILER_LABEL("TemporaryOriginInitializedOp::DoDirectoryWork", OTHER);
|
|
|
|
mInitialized = aQuotaManager.IsTemporaryOriginInitializedInternal(
|
|
OriginMetadata{mPrincipalMetadata, mPersistenceType});
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool TemporaryOriginInitializedOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return mInitialized;
|
|
}
|
|
|
|
InitOp::InitOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
RefPtr<UniversalDirectoryLock> aDirectoryLock)
|
|
: ResolvableNormalOriginOp(std::move(aQuotaManager), "dom::quota::InitOp"),
|
|
mDirectoryLock(std::move(aDirectoryLock)) {
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mDirectoryLock);
|
|
}
|
|
|
|
RefPtr<BoolPromise> InitOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mDirectoryLock);
|
|
|
|
return BoolPromise::CreateAndResolve(true, __func__);
|
|
}
|
|
|
|
nsresult InitOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
AUTO_PROFILER_LABEL("InitOp::DoDirectoryWork", OTHER);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(aQuotaManager.EnsureStorageIsInitializedInternal()));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool InitOp::GetResolveValue() { return true; }
|
|
|
|
void InitOp::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
DropDirectoryLock(mDirectoryLock);
|
|
}
|
|
|
|
InitTemporaryStorageOp::InitTemporaryStorageOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
RefPtr<UniversalDirectoryLock> aDirectoryLock)
|
|
: ResolvableNormalOriginOp(std::move(aQuotaManager),
|
|
"dom::quota::InitTemporaryStorageOp"),
|
|
mDirectoryLock(std::move(aDirectoryLock)) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
RefPtr<BoolPromise> InitTemporaryStorageOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mDirectoryLock);
|
|
|
|
return BoolPromise::CreateAndResolve(true, __func__);
|
|
}
|
|
|
|
nsresult InitTemporaryStorageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
AUTO_PROFILER_LABEL("InitTemporaryStorageOp::DoDirectoryWork", OTHER);
|
|
|
|
QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
|
|
NS_ERROR_NOT_INITIALIZED);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(
|
|
aQuotaManager.EnsureTemporaryStorageIsInitializedInternal()));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool InitTemporaryStorageOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return true;
|
|
}
|
|
|
|
void InitTemporaryStorageOp::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
DropDirectoryLock(mDirectoryLock);
|
|
}
|
|
|
|
InitializeOriginRequestBase::InitializeOriginRequestBase(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
|
|
const PrincipalInfo& aPrincipalInfo,
|
|
RefPtr<UniversalDirectoryLock> aDirectoryLock)
|
|
: ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
|
|
mPrincipalInfo(aPrincipalInfo),
|
|
mDirectoryLock(std::move(aDirectoryLock)),
|
|
mCreated(false) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult InitializeOriginRequestBase::DoInit(QuotaManager& aQuotaManager) {
|
|
AssertIsOnOwningThread();
|
|
|
|
QM_TRY_UNWRAP(
|
|
mPrincipalMetadata,
|
|
aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
|
|
|
|
mPrincipalMetadata.AssertInvariants();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<BoolPromise> InitializeOriginRequestBase::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mDirectoryLock);
|
|
|
|
return BoolPromise::CreateAndResolve(true, __func__);
|
|
}
|
|
|
|
void InitializeOriginRequestBase::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
DropDirectoryLockIfNotDropped(mDirectoryLock);
|
|
}
|
|
|
|
InitializePersistentOriginOp::InitializePersistentOriginOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const PrincipalInfo& aPrincipalInfo,
|
|
RefPtr<UniversalDirectoryLock> aDirectoryLock)
|
|
: InitializeOriginRequestBase(std::move(aQuotaManager),
|
|
"dom::quota::InitializePersistentOriginOp",
|
|
aPrincipalInfo, std::move(aDirectoryLock)) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult InitializePersistentOriginOp::DoDirectoryWork(
|
|
QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
AUTO_PROFILER_LABEL("InitializePersistentOriginOp::DoDirectoryWork", OTHER);
|
|
|
|
QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
|
|
NS_ERROR_NOT_INITIALIZED);
|
|
|
|
QM_TRY_UNWRAP(
|
|
mCreated,
|
|
(aQuotaManager
|
|
.EnsurePersistentOriginIsInitializedInternal(
|
|
OriginMetadata{mPrincipalMetadata, PERSISTENCE_TYPE_PERSISTENT})
|
|
.map([](const auto& res) { return res.second; })));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool InitializePersistentOriginOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return mCreated;
|
|
}
|
|
|
|
InitializeTemporaryOriginOp::InitializeTemporaryOriginOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
|
|
bool aCreateIfNonExistent, RefPtr<UniversalDirectoryLock> aDirectoryLock)
|
|
: InitializeOriginRequestBase(std::move(aQuotaManager),
|
|
"dom::quota::InitializeTemporaryOriginOp",
|
|
aPrincipalInfo, std::move(aDirectoryLock)),
|
|
mPersistenceType(aPersistenceType),
|
|
mCreateIfNonExistent(aCreateIfNonExistent) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult InitializeTemporaryOriginOp::DoDirectoryWork(
|
|
QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
AUTO_PROFILER_LABEL("InitializeTemporaryOriginOp::DoDirectoryWork", OTHER);
|
|
|
|
QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
|
|
NS_ERROR_NOT_INITIALIZED);
|
|
|
|
QM_TRY(OkIf(aQuotaManager.IsTemporaryStorageInitializedInternal()),
|
|
NS_ERROR_NOT_INITIALIZED);
|
|
|
|
QM_TRY_UNWRAP(mCreated,
|
|
(aQuotaManager
|
|
.EnsureTemporaryOriginIsInitializedInternal(
|
|
OriginMetadata{mPrincipalMetadata, mPersistenceType},
|
|
mCreateIfNonExistent)
|
|
.map([](const auto& res) { return res.second; })));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool InitializeTemporaryOriginOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return mCreated;
|
|
}
|
|
|
|
InitializeClientBase::InitializeClientBase(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
|
|
const PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
|
|
Client::Type aClientType)
|
|
: ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
|
|
mPrincipalInfo(aPrincipalInfo),
|
|
mPersistenceType(aPersistenceType),
|
|
mClientType(aClientType),
|
|
mCreated(false) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult InitializeClientBase::DoInit(QuotaManager& aQuotaManager) {
|
|
AssertIsOnOwningThread();
|
|
|
|
QM_TRY_UNWRAP(
|
|
PrincipalMetadata principalMetadata,
|
|
aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
|
|
|
|
principalMetadata.AssertInvariants();
|
|
|
|
mClientMetadata = {
|
|
OriginMetadata{std::move(principalMetadata), mPersistenceType},
|
|
mClientType};
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<BoolPromise> InitializeClientBase::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
|
|
PersistenceScope::CreateFromValue(mPersistenceType),
|
|
OriginScope::FromOrigin(mClientMetadata.mOrigin),
|
|
Nullable(mClientMetadata.mClientType), /* aExclusive */ false);
|
|
|
|
return mDirectoryLock->Acquire();
|
|
}
|
|
|
|
void InitializeClientBase::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
DropDirectoryLockIfNotDropped(mDirectoryLock);
|
|
}
|
|
|
|
InitializePersistentClientOp::InitializePersistentClientOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const PrincipalInfo& aPrincipalInfo, Client::Type aClientType)
|
|
: InitializeClientBase(
|
|
std::move(aQuotaManager), "dom::quota::InitializePersistentClientOp",
|
|
PERSISTENCE_TYPE_PERSISTENT, aPrincipalInfo, aClientType) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult InitializePersistentClientOp::DoDirectoryWork(
|
|
QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
AUTO_PROFILER_LABEL("InitializePersistentClientOp::DoDirectoryWork", OTHER);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsStorageInitializedInternal()),
|
|
NS_ERROR_FAILURE);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsPersistentOriginInitializedInternal(
|
|
mClientMetadata.mOrigin)),
|
|
NS_ERROR_FAILURE);
|
|
|
|
QM_TRY_UNWRAP(
|
|
mCreated,
|
|
(aQuotaManager.EnsurePersistentClientIsInitialized(mClientMetadata)
|
|
.map([](const auto& res) { return res.second; })));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool InitializePersistentClientOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return mCreated;
|
|
}
|
|
|
|
InitializeTemporaryClientOp::InitializeTemporaryClientOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
|
|
Client::Type aClientType)
|
|
: InitializeClientBase(std::move(aQuotaManager),
|
|
"dom::quota::InitializeTemporaryClientOp",
|
|
aPersistenceType, aPrincipalInfo, aClientType) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult InitializeTemporaryClientOp::DoDirectoryWork(
|
|
QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
AUTO_PROFILER_LABEL("InitializeTemporaryClientOp::DoDirectoryWork", OTHER);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsStorageInitializedInternal()),
|
|
NS_ERROR_FAILURE);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsTemporaryStorageInitializedInternal()),
|
|
NS_ERROR_FAILURE);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsTemporaryOriginInitializedInternal(
|
|
mClientMetadata)),
|
|
NS_ERROR_FAILURE);
|
|
|
|
QM_TRY_UNWRAP(
|
|
mCreated,
|
|
(aQuotaManager.EnsureTemporaryClientIsInitialized(mClientMetadata)
|
|
.map([](const auto& res) { return res.second; })));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool InitializeTemporaryClientOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return mCreated;
|
|
}
|
|
|
|
GetFullOriginMetadataOp::GetFullOriginMetadataOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const GetFullOriginMetadataParams& aParams)
|
|
: OpenStorageDirectoryHelper(std::move(aQuotaManager),
|
|
"dom::quota::GetFullOriginMetadataOp"),
|
|
mParams(aParams) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult GetFullOriginMetadataOp::DoInit(QuotaManager& aQuotaManager) {
|
|
AssertIsOnOwningThread();
|
|
|
|
QM_TRY_UNWRAP(
|
|
PrincipalMetadata principalMetadata,
|
|
aQuotaManager.GetInfoFromValidatedPrincipalInfo(mParams.principalInfo()));
|
|
|
|
principalMetadata.AssertInvariants();
|
|
|
|
mOriginMetadata = {std::move(principalMetadata), mParams.persistenceType()};
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<BoolPromise> GetFullOriginMetadataOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return OpenStorageDirectory(
|
|
PersistenceScope::CreateFromValue(mOriginMetadata.mPersistenceType),
|
|
OriginScope::FromOrigin(mOriginMetadata.mOrigin),
|
|
Nullable<Client::Type>(),
|
|
/* aExclusive */ false,
|
|
/* aInitializeOrigins */ true);
|
|
}
|
|
|
|
nsresult GetFullOriginMetadataOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
aQuotaManager.AssertStorageIsInitializedInternal();
|
|
|
|
AUTO_PROFILER_LABEL("GetFullOriginMetadataOp::DoDirectoryWork", OTHER);
|
|
|
|
// Get metadata cached in memory (the method doesn't have to stat any
|
|
// files).
|
|
mMaybeFullOriginMetadata =
|
|
aQuotaManager.GetFullOriginMetadata(mOriginMetadata);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void GetFullOriginMetadataOp::GetResponse(RequestResponse& aResponse) {
|
|
AssertIsOnOwningThread();
|
|
|
|
aResponse = GetFullOriginMetadataResponse();
|
|
aResponse.get_GetFullOriginMetadataResponse().maybeFullOriginMetadata() =
|
|
std::move(mMaybeFullOriginMetadata);
|
|
}
|
|
|
|
void GetFullOriginMetadataOp::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
SafeDropDirectoryLock(mDirectoryLock);
|
|
}
|
|
|
|
GetCachedOriginUsageOp::GetCachedOriginUsageOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const PrincipalInfo& aPrincipalInfo)
|
|
: OpenStorageDirectoryHelper(std::move(aQuotaManager),
|
|
"dom::quota::GetCachedOriginUsageOp"),
|
|
mPrincipalInfo(aPrincipalInfo),
|
|
mUsage(0) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult GetCachedOriginUsageOp::DoInit(QuotaManager& aQuotaManager) {
|
|
AssertIsOnOwningThread();
|
|
|
|
QM_TRY_UNWRAP(
|
|
mPrincipalMetadata,
|
|
aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
|
|
|
|
mPrincipalMetadata.AssertInvariants();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<BoolPromise> GetCachedOriginUsageOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return OpenStorageDirectory(
|
|
PersistenceScope::CreateFromSet(PERSISTENCE_TYPE_TEMPORARY,
|
|
PERSISTENCE_TYPE_DEFAULT,
|
|
PERSISTENCE_TYPE_PRIVATE),
|
|
OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
|
|
Nullable<Client::Type>(),
|
|
/* aExclusive */ false);
|
|
}
|
|
|
|
nsresult GetCachedOriginUsageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
MOZ_ASSERT(mUsage == 0);
|
|
|
|
AUTO_PROFILER_LABEL("GetCachedOriginUsageOp::DoDirectoryWork", OTHER);
|
|
|
|
// If temporary storage hasn't been initialized yet, there's no cached usage
|
|
// to report.
|
|
if (!aQuotaManager.IsTemporaryStorageInitializedInternal()) {
|
|
return NS_OK;
|
|
}
|
|
|
|
// Get cached usage (the method doesn't have to stat any files).
|
|
mUsage = aQuotaManager.GetOriginUsage(mPrincipalMetadata);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
uint64_t GetCachedOriginUsageOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return mUsage;
|
|
}
|
|
|
|
void GetCachedOriginUsageOp::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
SafeDropDirectoryLock(mDirectoryLock);
|
|
}
|
|
|
|
ClearStorageOp::ClearStorageOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
|
|
: OpenStorageDirectoryHelper(std::move(aQuotaManager),
|
|
"dom::quota::ClearStorageOp") {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
void ClearStorageOp::DeleteFiles(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
nsresult rv = aQuotaManager.AboutToClearOrigins(
|
|
PersistenceScope::CreateFromNull(), OriginScope::FromNull(),
|
|
Nullable<Client::Type>());
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return;
|
|
}
|
|
|
|
auto directoryOrErr = QM_NewLocalFile(aQuotaManager.GetStoragePath());
|
|
if (NS_WARN_IF(directoryOrErr.isErr())) {
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsIFile> directory = directoryOrErr.unwrap();
|
|
|
|
rv = directory->Remove(true);
|
|
if (rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
|
|
// This should never fail if we've closed all storage connections
|
|
// correctly...
|
|
MOZ_ASSERT(false, "Failed to remove storage directory!");
|
|
}
|
|
}
|
|
|
|
void ClearStorageOp::DeleteStorageFile(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
QM_TRY_INSPECT(const auto& storageFile,
|
|
QM_NewLocalFile(aQuotaManager.GetBasePath()), QM_VOID);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(storageFile->Append(aQuotaManager.GetStorageName() +
|
|
kSQLiteSuffix)),
|
|
QM_VOID);
|
|
|
|
const nsresult rv = storageFile->Remove(true);
|
|
if (rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
|
|
// This should never fail if we've closed the storage connection
|
|
// correctly...
|
|
MOZ_ASSERT(false, "Failed to remove storage file!");
|
|
}
|
|
}
|
|
|
|
RefPtr<BoolPromise> ClearStorageOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
// Clear directory lock tables (which also saves origin access time) before
|
|
// acquiring the exclusive lock below. Otherwise, saving of origin access
|
|
// time would be scheduled after storage clearing and that would initialize
|
|
// storage again in the end.
|
|
mQuotaManager->ClearDirectoryLockTables();
|
|
|
|
return OpenStorageDirectory(PersistenceScope::CreateFromNull(),
|
|
OriginScope::FromNull(), Nullable<Client::Type>(),
|
|
/* aExclusive */ true,
|
|
/* aInitializeOrigins */ false,
|
|
DirectoryLockCategory::UninitStorage);
|
|
}
|
|
|
|
nsresult ClearStorageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
aQuotaManager.AssertStorageIsInitializedInternal();
|
|
|
|
AUTO_PROFILER_LABEL("ClearStorageOp::DoDirectoryWork", OTHER);
|
|
|
|
DeleteFiles(aQuotaManager);
|
|
|
|
aQuotaManager.RemoveQuota();
|
|
|
|
aQuotaManager.ShutdownStorageInternal();
|
|
|
|
DeleteStorageFile(aQuotaManager);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool ClearStorageOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return true;
|
|
}
|
|
|
|
void ClearStorageOp::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
SafeDropDirectoryLock(mDirectoryLock);
|
|
}
|
|
|
|
void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
|
|
const OriginMetadata& aOriginMetadata) {
|
|
AssertIsOnIOThread();
|
|
|
|
DeleteFilesInternal(
|
|
aQuotaManager, aOriginMetadata.mPersistenceType,
|
|
OriginScope::FromOrigin(aOriginMetadata.mOrigin),
|
|
[&aQuotaManager, &aOriginMetadata](
|
|
const std::function<Result<Ok, nsresult>(nsCOMPtr<nsIFile>)>& aBody)
|
|
-> Result<Ok, nsresult> {
|
|
QM_TRY_UNWRAP(auto directory,
|
|
aQuotaManager.GetOriginDirectory(aOriginMetadata));
|
|
|
|
// We're not checking if the origin directory actualy exists because
|
|
// it can be a pending origin (OriginInfo does exist but the origin
|
|
// directory hasn't been created yet).
|
|
|
|
QM_TRY_RETURN(aBody(std::move(directory)));
|
|
});
|
|
}
|
|
|
|
void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
|
|
PersistenceType aPersistenceType,
|
|
const OriginScope& aOriginScope) {
|
|
AssertIsOnIOThread();
|
|
|
|
DeleteFilesInternal(
|
|
aQuotaManager, aPersistenceType, aOriginScope,
|
|
[&aQuotaManager, &aPersistenceType](
|
|
const std::function<Result<Ok, nsresult>(nsCOMPtr<nsIFile>)>& aBody)
|
|
-> Result<Ok, nsresult> {
|
|
QM_TRY_INSPECT(
|
|
const auto& directory,
|
|
QM_NewLocalFile(aQuotaManager.GetStoragePath(aPersistenceType)));
|
|
|
|
QM_TRY_INSPECT(const bool& exists,
|
|
MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
|
|
|
|
if (!exists) {
|
|
return Ok{};
|
|
}
|
|
|
|
QM_TRY(CollectEachFile(*directory, aBody));
|
|
|
|
// CollectEachFile above only consulted the file-system to get a list of
|
|
// known origins, but we also need to include origins that have pending
|
|
// quota usage.
|
|
|
|
nsTArray<OriginMetadata> originMetadataArray;
|
|
aQuotaManager.CollectPendingOriginsForListing(
|
|
[aPersistenceType, &originMetadataArray](const auto& originInfo) {
|
|
if (originInfo->GetGroupInfo()->GetPersistenceType() !=
|
|
aPersistenceType) {
|
|
return;
|
|
}
|
|
originMetadataArray.AppendElement(
|
|
originInfo->FlattenToOriginMetadata());
|
|
});
|
|
|
|
if (originMetadataArray.IsEmpty()) {
|
|
return Ok{};
|
|
}
|
|
|
|
nsTArray<nsCOMPtr<nsIFile>> originDirectories;
|
|
QM_TRY(TransformAbortOnErr(
|
|
originMetadataArray, MakeBackInserter(originDirectories),
|
|
[&aQuotaManager](const auto& originMetadata)
|
|
-> Result<nsCOMPtr<nsIFile>, nsresult> {
|
|
QM_TRY_UNWRAP(auto originDirectory,
|
|
aQuotaManager.GetOriginDirectory(originMetadata));
|
|
return originDirectory;
|
|
}));
|
|
|
|
QM_TRY_RETURN(CollectEachInRange(originDirectories, aBody));
|
|
});
|
|
}
|
|
|
|
template <typename FileCollector>
|
|
void ClearRequestBase::DeleteFilesInternal(
|
|
QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
|
|
const OriginScope& aOriginScope, const FileCollector& aFileCollector) {
|
|
AssertIsOnIOThread();
|
|
|
|
QM_TRY(MOZ_TO_RESULT(aQuotaManager.AboutToClearOrigins(
|
|
PersistenceScope::CreateFromValue(aPersistenceType), aOriginScope,
|
|
Nullable<Client::Type>())),
|
|
QM_VOID);
|
|
|
|
nsTArray<nsCOMPtr<nsIFile>> directoriesForRemovalRetry;
|
|
|
|
aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
|
|
"ClearRequestBase: Starting deleting files"_ns);
|
|
|
|
QM_TRY(
|
|
aFileCollector([&originScope = aOriginScope, aPersistenceType,
|
|
&aQuotaManager, &directoriesForRemovalRetry,
|
|
this](nsCOMPtr<nsIFile> file)
|
|
-> mozilla::Result<Ok, nsresult> {
|
|
QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*file));
|
|
|
|
QM_TRY_INSPECT(
|
|
const auto& leafName,
|
|
MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, file, GetLeafName));
|
|
|
|
switch (dirEntryKind) {
|
|
case nsIFileKind::ExistsAsDirectory: {
|
|
QM_TRY_UNWRAP(auto maybeMetadata,
|
|
QM_OR_ELSE_WARN_IF(
|
|
// Expression
|
|
aQuotaManager.GetOriginMetadata(file).map(
|
|
[](auto metadata) -> Maybe<OriginMetadata> {
|
|
return Some(std::move(metadata));
|
|
}),
|
|
// Predicate.
|
|
IsSpecificError<NS_ERROR_MALFORMED_URI>,
|
|
// Fallback.
|
|
ErrToDefaultOk<Maybe<OriginMetadata>>));
|
|
|
|
if (!maybeMetadata) {
|
|
// Unknown directories during clearing are allowed. Just
|
|
// warn if we find them.
|
|
UNKNOWN_FILE_WARNING(leafName);
|
|
break;
|
|
}
|
|
|
|
auto metadata = maybeMetadata.extract();
|
|
|
|
MOZ_ASSERT(metadata.mPersistenceType == aPersistenceType);
|
|
|
|
// Skip the origin directory if it doesn't match the pattern.
|
|
if (!originScope.Matches(
|
|
OriginScope::FromOrigin(metadata.mOrigin))) {
|
|
break;
|
|
}
|
|
|
|
// We can't guarantee that this will always succeed on
|
|
// Windows...
|
|
QM_WARNONLY_TRY(
|
|
aQuotaManager.RemoveOriginDirectory(*file), [&](const auto&) {
|
|
directoriesForRemovalRetry.AppendElement(std::move(file));
|
|
});
|
|
|
|
mOriginMetadataArray.AppendElement(metadata);
|
|
|
|
const bool initialized =
|
|
aPersistenceType == PERSISTENCE_TYPE_PERSISTENT
|
|
? aQuotaManager.IsPersistentOriginInitializedInternal(
|
|
metadata.mOrigin)
|
|
: aQuotaManager.IsTemporaryStorageInitializedInternal();
|
|
|
|
// If it hasn't been initialized, we don't need to update the
|
|
// quota and notify the removing client, but we do need to remove
|
|
// it from quota info cache.
|
|
if (!initialized) {
|
|
aQuotaManager.RemoveOriginFromCache(metadata);
|
|
break;
|
|
}
|
|
|
|
if (aPersistenceType != PERSISTENCE_TYPE_PERSISTENT) {
|
|
aQuotaManager.RemoveQuotaForOrigin(aPersistenceType, metadata);
|
|
}
|
|
|
|
aQuotaManager.OriginClearCompleted(
|
|
aPersistenceType, metadata.mOrigin, Nullable<Client::Type>());
|
|
|
|
break;
|
|
}
|
|
|
|
case nsIFileKind::ExistsAsFile: {
|
|
// Unknown files during clearing are allowed. Just warn if we
|
|
// find them.
|
|
if (!IsOSMetadata(leafName)) {
|
|
UNKNOWN_FILE_WARNING(leafName);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case nsIFileKind::DoesNotExist: {
|
|
if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
|
|
break;
|
|
}
|
|
|
|
QM_TRY_UNWRAP(auto metadata, aQuotaManager.GetOriginMetadata(file));
|
|
|
|
MOZ_ASSERT(metadata.mPersistenceType == aPersistenceType);
|
|
|
|
// Skip the origin directory if it doesn't match the pattern.
|
|
if (!originScope.Matches(
|
|
OriginScope::FromOrigin(metadata.mOrigin))) {
|
|
break;
|
|
}
|
|
|
|
if (!aQuotaManager.IsPendingOrigin(metadata)) {
|
|
break;
|
|
}
|
|
|
|
mOriginMetadataArray.AppendElement(metadata);
|
|
|
|
aQuotaManager.RemoveQuotaForOrigin(aPersistenceType, metadata);
|
|
|
|
aQuotaManager.OriginClearCompleted(
|
|
aPersistenceType, metadata.mOrigin, Nullable<Client::Type>());
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
mIterations++;
|
|
|
|
return Ok{};
|
|
}),
|
|
QM_VOID);
|
|
|
|
// Retry removing any directories that failed to be removed earlier now.
|
|
//
|
|
// XXX This will still block this operation. We might instead dispatch a
|
|
// runnable to our own thread for each retry round with a timer. We must
|
|
// ensure that the directory lock is upheld until we complete or give up
|
|
// though.
|
|
for (uint32_t index = 0; index < 10; index++) {
|
|
aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
|
|
return nsPrintfCString(
|
|
"ClearRequestBase: Starting repeated directory removal #%d", index);
|
|
});
|
|
|
|
for (auto&& file : std::exchange(directoriesForRemovalRetry,
|
|
nsTArray<nsCOMPtr<nsIFile>>{})) {
|
|
QM_WARNONLY_TRY(
|
|
aQuotaManager.RemoveOriginDirectory(*file),
|
|
([&directoriesForRemovalRetry, &file](const auto&) {
|
|
directoriesForRemovalRetry.AppendElement(std::move(file));
|
|
}));
|
|
}
|
|
|
|
aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
|
|
return nsPrintfCString(
|
|
"ClearRequestBase: Completed repeated directory removal #%d", index);
|
|
});
|
|
|
|
if (directoriesForRemovalRetry.IsEmpty()) {
|
|
break;
|
|
}
|
|
|
|
aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
|
|
return nsPrintfCString("ClearRequestBase: Before sleep #%d", index);
|
|
});
|
|
|
|
PR_Sleep(PR_MillisecondsToInterval(200));
|
|
|
|
aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
|
|
return nsPrintfCString("ClearRequestBase: After sleep #%d", index);
|
|
});
|
|
}
|
|
|
|
QM_WARNONLY_TRY(OkIf(directoriesForRemovalRetry.IsEmpty()));
|
|
|
|
aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
|
|
"ClearRequestBase: Completed deleting files"_ns);
|
|
}
|
|
|
|
ClearOriginOp::ClearOriginOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const mozilla::Maybe<PersistenceType>& aPersistenceType,
|
|
const PrincipalInfo& aPrincipalInfo)
|
|
: ClearRequestBase(std::move(aQuotaManager), "dom::quota::ClearOriginOp"),
|
|
mPrincipalInfo(aPrincipalInfo),
|
|
mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
|
|
*aPersistenceType)
|
|
: PersistenceScope::CreateFromNull()) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult ClearOriginOp::DoInit(QuotaManager& aQuotaManager) {
|
|
AssertIsOnOwningThread();
|
|
|
|
QM_TRY_UNWRAP(
|
|
mPrincipalMetadata,
|
|
aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
|
|
|
|
mPrincipalMetadata.AssertInvariants();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<BoolPromise> ClearOriginOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return OpenStorageDirectory(
|
|
mPersistenceScope, OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
|
|
Nullable<Client::Type>(), /* aExclusive */ true,
|
|
/* aInitializeOrigins */ false, DirectoryLockCategory::UninitOrigins);
|
|
}
|
|
|
|
nsresult ClearOriginOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
aQuotaManager.AssertStorageIsInitializedInternal();
|
|
|
|
AUTO_PROFILER_LABEL("ClearRequestBase::DoDirectoryWork", OTHER);
|
|
|
|
if (mPersistenceScope.IsNull()) {
|
|
for (const PersistenceType type : kAllPersistenceTypes) {
|
|
DeleteFiles(aQuotaManager, OriginMetadata(mPrincipalMetadata, type));
|
|
}
|
|
} else {
|
|
MOZ_ASSERT(mPersistenceScope.IsValue());
|
|
|
|
DeleteFiles(aQuotaManager, OriginMetadata(mPrincipalMetadata,
|
|
mPersistenceScope.GetValue()));
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
OriginMetadataArray ClearOriginOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return std::move(mOriginMetadataArray);
|
|
}
|
|
|
|
void ClearOriginOp::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
SafeDropDirectoryLock(mDirectoryLock);
|
|
}
|
|
|
|
ClearClientOp::ClearClientOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
mozilla::Maybe<PersistenceType> aPersistenceType,
|
|
const PrincipalInfo& aPrincipalInfo,
|
|
Client::Type aClientType)
|
|
: OpenStorageDirectoryHelper(std::move(aQuotaManager),
|
|
"dom::quota::ClearClientOp"),
|
|
mPrincipalInfo(aPrincipalInfo),
|
|
mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
|
|
*aPersistenceType)
|
|
: PersistenceScope::CreateFromNull()),
|
|
mClientType(aClientType) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult ClearClientOp::DoInit(QuotaManager& aQuotaManager) {
|
|
AssertIsOnOwningThread();
|
|
|
|
QM_TRY_UNWRAP(
|
|
mPrincipalMetadata,
|
|
aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
|
|
|
|
mPrincipalMetadata.AssertInvariants();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<BoolPromise> ClearClientOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return OpenStorageDirectory(
|
|
mPersistenceScope, OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
|
|
Nullable(mClientType), /* aExclusive */ true);
|
|
}
|
|
|
|
void ClearClientOp::DeleteFiles(const ClientMetadata& aClientMetadata) {
|
|
AssertIsOnIOThread();
|
|
|
|
QM_TRY(
|
|
MOZ_TO_RESULT(mQuotaManager->AboutToClearOrigins(
|
|
PersistenceScope::CreateFromValue(aClientMetadata.mPersistenceType),
|
|
OriginScope::FromOrigin(aClientMetadata.mOrigin),
|
|
Nullable(aClientMetadata.mClientType))),
|
|
QM_VOID);
|
|
|
|
QM_TRY_INSPECT(const auto& directory,
|
|
mQuotaManager->GetOriginDirectory(aClientMetadata), QM_VOID);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(directory->Append(
|
|
Client::TypeToString(aClientMetadata.mClientType))),
|
|
QM_VOID);
|
|
|
|
QM_TRY_INSPECT(const bool& exists,
|
|
MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists), QM_VOID);
|
|
if (!exists) {
|
|
return;
|
|
}
|
|
|
|
QM_TRY(MOZ_TO_RESULT(directory->Remove(true)), QM_VOID);
|
|
|
|
const bool initialized =
|
|
aClientMetadata.mPersistenceType == PERSISTENCE_TYPE_PERSISTENT
|
|
? mQuotaManager->IsPersistentOriginInitializedInternal(
|
|
aClientMetadata.mOrigin)
|
|
: mQuotaManager->IsTemporaryStorageInitializedInternal();
|
|
|
|
if (!initialized) {
|
|
return;
|
|
}
|
|
|
|
if (aClientMetadata.mPersistenceType != PERSISTENCE_TYPE_PERSISTENT) {
|
|
mQuotaManager->ResetUsageForClient(aClientMetadata);
|
|
}
|
|
|
|
mQuotaManager->OriginClearCompleted(aClientMetadata.mPersistenceType,
|
|
aClientMetadata.mOrigin,
|
|
Nullable(aClientMetadata.mClientType));
|
|
}
|
|
|
|
nsresult ClearClientOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
aQuotaManager.AssertStorageIsInitializedInternal();
|
|
|
|
AUTO_PROFILER_LABEL("ClearClientOp::DoDirectoryWork", OTHER);
|
|
|
|
if (mPersistenceScope.IsNull()) {
|
|
for (const PersistenceType type : kAllPersistenceTypes) {
|
|
DeleteFiles(ClientMetadata(OriginMetadata(mPrincipalMetadata, type),
|
|
mClientType));
|
|
}
|
|
} else {
|
|
MOZ_ASSERT(mPersistenceScope.IsValue());
|
|
|
|
DeleteFiles(ClientMetadata(
|
|
OriginMetadata(mPrincipalMetadata, mPersistenceScope.GetValue()),
|
|
mClientType));
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool ClearClientOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return true;
|
|
}
|
|
|
|
void ClearClientOp::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
SafeDropDirectoryLock(mDirectoryLock);
|
|
}
|
|
|
|
ClearStoragesForOriginPrefixOp::ClearStoragesForOriginPrefixOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const Maybe<PersistenceType>& aPersistenceType,
|
|
const PrincipalInfo& aPrincipalInfo)
|
|
: OpenStorageDirectoryHelper(std::move(aQuotaManager),
|
|
"dom::quota::ClearStoragesForOriginPrefixOp"),
|
|
mPrefix(
|
|
QuotaManager::GetOriginFromValidatedPrincipalInfo(aPrincipalInfo)),
|
|
mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
|
|
*aPersistenceType)
|
|
: PersistenceScope::CreateFromNull()) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
RefPtr<BoolPromise> ClearStoragesForOriginPrefixOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return OpenStorageDirectory(
|
|
mPersistenceScope, OriginScope::FromPrefix(mPrefix),
|
|
Nullable<Client::Type>(), /* aExclusive */ true,
|
|
/* aInitializeOrigins */ false, DirectoryLockCategory::UninitOrigins);
|
|
}
|
|
|
|
nsresult ClearStoragesForOriginPrefixOp::DoDirectoryWork(
|
|
QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
AUTO_PROFILER_LABEL("ClearStoragesForOriginPrefixOp::DoDirectoryWork", OTHER);
|
|
|
|
if (mPersistenceScope.IsNull()) {
|
|
for (const PersistenceType type : kAllPersistenceTypes) {
|
|
DeleteFiles(aQuotaManager, type, OriginScope::FromPrefix(mPrefix));
|
|
}
|
|
} else {
|
|
MOZ_ASSERT(mPersistenceScope.IsValue());
|
|
|
|
DeleteFiles(aQuotaManager, mPersistenceScope.GetValue(),
|
|
OriginScope::FromPrefix(mPrefix));
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
OriginMetadataArray ClearStoragesForOriginPrefixOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return std::move(mOriginMetadataArray);
|
|
}
|
|
|
|
void ClearStoragesForOriginPrefixOp::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
SafeDropDirectoryLock(mDirectoryLock);
|
|
}
|
|
|
|
ClearDataOp::ClearDataOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const OriginAttributesPattern& aPattern)
|
|
: ClearRequestBase(std::move(aQuotaManager), "dom::quota::ClearDataOp"),
|
|
mPattern(aPattern) {}
|
|
|
|
RefPtr<BoolPromise> ClearDataOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return OpenStorageDirectory(
|
|
PersistenceScope::CreateFromNull(), OriginScope::FromPattern(mPattern),
|
|
Nullable<Client::Type>(), /* aExclusive */ true,
|
|
/* aInitializeOrigins */ false, DirectoryLockCategory::UninitOrigins);
|
|
}
|
|
|
|
nsresult ClearDataOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
AUTO_PROFILER_LABEL("ClearRequestBase::DoDirectoryWork", OTHER);
|
|
|
|
for (const PersistenceType type : kAllPersistenceTypes) {
|
|
DeleteFiles(aQuotaManager, type, OriginScope::FromPattern(mPattern));
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
OriginMetadataArray ClearDataOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return std::move(mOriginMetadataArray);
|
|
}
|
|
|
|
void ClearDataOp::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
SafeDropDirectoryLock(mDirectoryLock);
|
|
}
|
|
|
|
ShutdownOriginOp::ShutdownOriginOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
mozilla::Maybe<PersistenceType> aPersistenceType,
|
|
const PrincipalInfo& aPrincipalInfo)
|
|
: ResolvableNormalOriginOp(std::move(aQuotaManager),
|
|
"dom::quota::ShutdownOriginOp"),
|
|
mPrincipalInfo(aPrincipalInfo),
|
|
mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
|
|
*aPersistenceType)
|
|
: PersistenceScope::CreateFromNull()) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult ShutdownOriginOp::DoInit(QuotaManager& aQuotaManager) {
|
|
AssertIsOnOwningThread();
|
|
|
|
QM_TRY_UNWRAP(
|
|
mPrincipalMetadata,
|
|
aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
|
|
|
|
mPrincipalMetadata.AssertInvariants();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<BoolPromise> ShutdownOriginOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
|
|
mPersistenceScope, OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
|
|
Nullable<Client::Type>(), /* aExclusive */ true,
|
|
DirectoryLockCategory::UninitOrigins);
|
|
|
|
return mDirectoryLock->Acquire();
|
|
}
|
|
|
|
void ShutdownOriginOp::CollectOriginMetadata(
|
|
const OriginMetadata& aOriginMetadata) {
|
|
AssertIsOnIOThread();
|
|
|
|
QM_TRY_INSPECT(const auto& directory,
|
|
mQuotaManager->GetOriginDirectory(aOriginMetadata), QM_VOID);
|
|
|
|
QM_TRY_INSPECT(const bool& exists,
|
|
MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists), QM_VOID);
|
|
if (!exists) {
|
|
if (aOriginMetadata.mPersistenceType != PERSISTENCE_TYPE_PERSISTENT &&
|
|
mQuotaManager->IsPendingOrigin(aOriginMetadata)) {
|
|
mOriginMetadataArray.AppendElement(aOriginMetadata);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
mOriginMetadataArray.AppendElement(aOriginMetadata);
|
|
}
|
|
|
|
nsresult ShutdownOriginOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
AUTO_PROFILER_LABEL("ShutdownOriginOp::DoDirectoryWork", OTHER);
|
|
|
|
if (mPersistenceScope.IsNull()) {
|
|
for (const PersistenceType type : kAllPersistenceTypes) {
|
|
CollectOriginMetadata(OriginMetadata(mPrincipalMetadata, type));
|
|
}
|
|
} else {
|
|
MOZ_ASSERT(mPersistenceScope.IsValue());
|
|
|
|
CollectOriginMetadata(
|
|
OriginMetadata(mPrincipalMetadata, mPersistenceScope.GetValue()));
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
OriginMetadataArray ShutdownOriginOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return std::move(mOriginMetadataArray);
|
|
}
|
|
|
|
void ShutdownOriginOp::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
DropDirectoryLockIfNotDropped(mDirectoryLock);
|
|
}
|
|
|
|
ShutdownClientOp::ShutdownClientOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
mozilla::Maybe<PersistenceType> aPersistenceType,
|
|
const PrincipalInfo& aPrincipalInfo, Client::Type aClientType)
|
|
: ResolvableNormalOriginOp(std::move(aQuotaManager),
|
|
"dom::quota::ShutdownClientOp"),
|
|
mPrincipalInfo(aPrincipalInfo),
|
|
mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
|
|
*aPersistenceType)
|
|
: PersistenceScope::CreateFromNull()),
|
|
mClientType(aClientType) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult ShutdownClientOp::DoInit(QuotaManager& aQuotaManager) {
|
|
AssertIsOnOwningThread();
|
|
|
|
QM_TRY_UNWRAP(
|
|
mPrincipalMetadata,
|
|
aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
|
|
|
|
mPrincipalMetadata.AssertInvariants();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<BoolPromise> ShutdownClientOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
|
|
mPersistenceScope, OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
|
|
Nullable(mClientType), /* aExclusive */ true);
|
|
|
|
return mDirectoryLock->Acquire();
|
|
}
|
|
|
|
nsresult ShutdownClientOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
AUTO_PROFILER_LABEL("ShutdownClientOp::DoDirectoryWork", OTHER);
|
|
|
|
// All the work is handled by NormalOriginOperationBase parent class. In
|
|
// this particular case, we just needed to acquire an exclusive directory
|
|
// lock and that's it.
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool ShutdownClientOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return true;
|
|
}
|
|
|
|
void ShutdownClientOp::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
DropDirectoryLockIfNotDropped(mDirectoryLock);
|
|
}
|
|
|
|
PersistRequestBase::PersistRequestBase(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const PrincipalInfo& aPrincipalInfo)
|
|
: OpenStorageDirectoryHelper(std::move(aQuotaManager),
|
|
"dom::quota::PersistRequestBase"),
|
|
mPrincipalInfo(aPrincipalInfo) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult PersistRequestBase::DoInit(QuotaManager& aQuotaManager) {
|
|
AssertIsOnOwningThread();
|
|
|
|
// Figure out which origin we're dealing with.
|
|
QM_TRY_UNWRAP(
|
|
mPrincipalMetadata,
|
|
aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
|
|
|
|
mPrincipalMetadata.AssertInvariants();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<BoolPromise> PersistRequestBase::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return OpenStorageDirectory(
|
|
PersistenceScope::CreateFromValue(PERSISTENCE_TYPE_DEFAULT),
|
|
OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
|
|
Nullable<Client::Type>(),
|
|
/* aExclusive */ false);
|
|
}
|
|
|
|
void PersistRequestBase::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
SafeDropDirectoryLock(mDirectoryLock);
|
|
}
|
|
|
|
PersistedOp::PersistedOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const RequestParams& aParams)
|
|
: PersistRequestBase(std::move(aQuotaManager),
|
|
aParams.get_PersistedParams().principalInfo()),
|
|
mPersisted(false) {
|
|
MOZ_ASSERT(aParams.type() == RequestParams::TPersistedParams);
|
|
}
|
|
|
|
nsresult PersistedOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
aQuotaManager.AssertStorageIsInitializedInternal();
|
|
|
|
AUTO_PROFILER_LABEL("PersistedOp::DoDirectoryWork", OTHER);
|
|
|
|
const OriginMetadata originMetadata = {mPrincipalMetadata,
|
|
PERSISTENCE_TYPE_DEFAULT};
|
|
|
|
Nullable<bool> persisted = aQuotaManager.OriginPersisted(originMetadata);
|
|
|
|
if (!persisted.IsNull()) {
|
|
mPersisted = persisted.Value();
|
|
return NS_OK;
|
|
}
|
|
|
|
// If we get here, it means the origin hasn't been initialized yet.
|
|
// Try to get the persisted flag from directory metadata on disk.
|
|
|
|
QM_TRY_INSPECT(const auto& directory,
|
|
aQuotaManager.GetOriginDirectory(originMetadata));
|
|
|
|
QM_TRY_INSPECT(const bool& exists,
|
|
MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
|
|
|
|
if (exists) {
|
|
// Get the metadata. We only use the persisted flag.
|
|
QM_TRY_INSPECT(const auto& metadata,
|
|
aQuotaManager.LoadFullOriginMetadataWithRestore(directory));
|
|
|
|
mPersisted = metadata.mPersisted;
|
|
} else {
|
|
// The directory has not been created yet.
|
|
mPersisted = false;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void PersistedOp::GetResponse(RequestResponse& aResponse) {
|
|
AssertIsOnOwningThread();
|
|
|
|
PersistedResponse persistedResponse;
|
|
persistedResponse.persisted() = mPersisted;
|
|
|
|
aResponse = persistedResponse;
|
|
}
|
|
|
|
PersistOp::PersistOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const RequestParams& aParams)
|
|
: PersistRequestBase(std::move(aQuotaManager),
|
|
aParams.get_PersistParams().principalInfo()) {
|
|
MOZ_ASSERT(aParams.type() == RequestParams::TPersistParams);
|
|
}
|
|
|
|
nsresult PersistOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
aQuotaManager.AssertStorageIsInitializedInternal();
|
|
|
|
const OriginMetadata originMetadata = {mPrincipalMetadata,
|
|
PERSISTENCE_TYPE_DEFAULT};
|
|
|
|
AUTO_PROFILER_LABEL("PersistOp::DoDirectoryWork", OTHER);
|
|
|
|
// Update directory metadata on disk first. Then, create/update the
|
|
// originInfo if needed.
|
|
|
|
QM_TRY_INSPECT(const auto& directory,
|
|
aQuotaManager.GetOriginDirectory(originMetadata));
|
|
|
|
QM_TRY_INSPECT(const bool& created,
|
|
aQuotaManager.EnsureOriginDirectory(*directory));
|
|
|
|
if (created) {
|
|
// A new origin directory has been created.
|
|
|
|
// XXX The code below could be converted to a function which returns the
|
|
// timestamp.
|
|
int64_t timestamp;
|
|
|
|
// Update OriginInfo too if temporary origin was already initialized.
|
|
if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
|
|
if (aQuotaManager.IsTemporaryOriginInitializedInternal(originMetadata)) {
|
|
// We have a temporary origin which has been initialized without
|
|
// ensuring respective origin directory. So OriginInfo already exists
|
|
// and it needs to be updated because the origin directory has been
|
|
// just created.
|
|
|
|
timestamp = aQuotaManager.WithOriginInfo(
|
|
originMetadata, [](const auto& originInfo) {
|
|
const int64_t timestamp = originInfo->LockedAccessTime();
|
|
|
|
originInfo->LockedDirectoryCreated();
|
|
|
|
return timestamp;
|
|
});
|
|
} else {
|
|
timestamp = PR_Now();
|
|
}
|
|
} else {
|
|
timestamp = PR_Now();
|
|
}
|
|
|
|
QM_TRY(MOZ_TO_RESULT(QuotaManager::CreateDirectoryMetadata2(
|
|
*directory, timestamp, /* aPersisted */ true, originMetadata)));
|
|
|
|
// Update or create OriginInfo too if temporary storage was already
|
|
// initialized.
|
|
if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
|
|
if (aQuotaManager.IsTemporaryOriginInitializedInternal(originMetadata)) {
|
|
// In this case, we have a temporary origin which has been initialized
|
|
// without ensuring respective origin directory. So OriginInfo already
|
|
// exists and it needs to be updated because the origin directory has
|
|
// been just created.
|
|
|
|
aQuotaManager.PersistOrigin(originMetadata);
|
|
} else {
|
|
// In this case, we have a temporary origin which hasn't been
|
|
// initialized yet. So OriginInfo needs to be created because the
|
|
// origin directory has been just created.
|
|
|
|
aQuotaManager.InitQuotaForOrigin(
|
|
FullOriginMetadata{originMetadata, /* aPersisted */ true,
|
|
timestamp},
|
|
ClientUsageArray(), /* aUsageBytes */ 0);
|
|
}
|
|
}
|
|
} else {
|
|
QM_TRY_INSPECT(
|
|
const bool& persisted,
|
|
([&aQuotaManager, &originMetadata,
|
|
&directory]() -> mozilla::Result<bool, nsresult> {
|
|
Nullable<bool> persisted =
|
|
aQuotaManager.OriginPersisted(originMetadata);
|
|
|
|
if (!persisted.IsNull()) {
|
|
return persisted.Value();
|
|
}
|
|
|
|
// Get the metadata (restore the metadata file if necessary). We only
|
|
// use the persisted flag.
|
|
QM_TRY_INSPECT(
|
|
const auto& metadata,
|
|
aQuotaManager.LoadFullOriginMetadataWithRestore(directory));
|
|
|
|
return metadata.mPersisted;
|
|
}()));
|
|
|
|
if (!persisted) {
|
|
QM_TRY_INSPECT(const auto& file,
|
|
CloneFileAndAppend(
|
|
*directory, nsLiteralString(METADATA_V2_FILE_NAME)));
|
|
|
|
QM_TRY_INSPECT(const auto& stream,
|
|
GetBinaryOutputStream(*file, FileFlag::Update));
|
|
|
|
MOZ_ASSERT(stream);
|
|
|
|
// Update origin access time while we are here.
|
|
QM_TRY(MOZ_TO_RESULT(stream->Write64(PR_Now())));
|
|
|
|
// Set the persisted flag to true.
|
|
QM_TRY(MOZ_TO_RESULT(stream->WriteBoolean(true)));
|
|
|
|
QM_TRY(MOZ_TO_RESULT(stream->Close()));
|
|
|
|
// Directory metadata has been successfully updated.
|
|
// Update OriginInfo too if temporary storage was already initialized.
|
|
if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
|
|
aQuotaManager.PersistOrigin(originMetadata);
|
|
}
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void PersistOp::GetResponse(RequestResponse& aResponse) {
|
|
AssertIsOnOwningThread();
|
|
|
|
aResponse = PersistResponse();
|
|
}
|
|
|
|
EstimateOp::EstimateOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const EstimateParams& aParams)
|
|
: OpenStorageDirectoryHelper(std::move(aQuotaManager),
|
|
"dom::quota::EstimateOp"),
|
|
mParams(aParams) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult EstimateOp::DoInit(QuotaManager& aQuotaManager) {
|
|
AssertIsOnOwningThread();
|
|
|
|
QM_TRY_UNWRAP(
|
|
PrincipalMetadata principalMetadata,
|
|
aQuotaManager.GetInfoFromValidatedPrincipalInfo(mParams.principalInfo()));
|
|
|
|
principalMetadata.AssertInvariants();
|
|
|
|
mOriginMetadata = {std::move(principalMetadata), PERSISTENCE_TYPE_DEFAULT};
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<BoolPromise> EstimateOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
// XXX In theory, we should be locking entire group, not just one origin.
|
|
return OpenStorageDirectory(
|
|
PersistenceScope::CreateFromSet(PERSISTENCE_TYPE_TEMPORARY,
|
|
PERSISTENCE_TYPE_DEFAULT,
|
|
PERSISTENCE_TYPE_PRIVATE),
|
|
OriginScope::FromOrigin(mOriginMetadata.mOrigin),
|
|
Nullable<Client::Type>(),
|
|
/* aExclusive */ false,
|
|
/* aInitializeOrigins */ true);
|
|
}
|
|
|
|
nsresult EstimateOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
aQuotaManager.AssertStorageIsInitializedInternal();
|
|
|
|
AUTO_PROFILER_LABEL("EstimateOp::DoDirectoryWork", OTHER);
|
|
|
|
// Get cached usage (the method doesn't have to stat any files).
|
|
mUsageAndLimit = aQuotaManager.GetUsageAndLimitForEstimate(mOriginMetadata);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void EstimateOp::GetResponse(RequestResponse& aResponse) {
|
|
AssertIsOnOwningThread();
|
|
|
|
EstimateResponse estimateResponse;
|
|
|
|
estimateResponse.usage() = mUsageAndLimit.first;
|
|
estimateResponse.limit() = mUsageAndLimit.second;
|
|
|
|
aResponse = estimateResponse;
|
|
}
|
|
|
|
void EstimateOp::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
SafeDropDirectoryLock(mDirectoryLock);
|
|
}
|
|
|
|
ListOriginsOp::ListOriginsOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
|
|
: OpenStorageDirectoryHelper(std::move(aQuotaManager),
|
|
"dom::quota::ListOriginsOp") {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
RefPtr<BoolPromise> ListOriginsOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return OpenStorageDirectory(PersistenceScope::CreateFromNull(),
|
|
OriginScope::FromNull(), Nullable<Client::Type>(),
|
|
/* aExclusive */ false);
|
|
}
|
|
|
|
nsresult ListOriginsOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
aQuotaManager.AssertStorageIsInitializedInternal();
|
|
|
|
AUTO_PROFILER_LABEL("ListOriginsOp::DoDirectoryWork", OTHER);
|
|
|
|
for (const PersistenceType type : kAllPersistenceTypes) {
|
|
QM_TRY(MOZ_TO_RESULT(TraverseRepository(aQuotaManager, type)));
|
|
}
|
|
|
|
// TraverseRepository above only consulted the file-system to get a list of
|
|
// known origins, but we also need to include origins that have pending
|
|
// quota usage.
|
|
|
|
aQuotaManager.CollectPendingOriginsForListing([this](const auto& originInfo) {
|
|
mOrigins.AppendElement(originInfo->Origin());
|
|
});
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
const Atomic<bool>& ListOriginsOp::GetIsCanceledFlag() {
|
|
AssertIsOnIOThread();
|
|
|
|
return Canceled();
|
|
}
|
|
|
|
nsresult ListOriginsOp::ProcessOrigin(QuotaManager& aQuotaManager,
|
|
nsIFile& aOriginDir,
|
|
const bool aPersistent,
|
|
const PersistenceType aPersistenceType) {
|
|
AssertIsOnIOThread();
|
|
|
|
QM_TRY_UNWRAP(auto maybeMetadata,
|
|
QM_OR_ELSE_WARN_IF(
|
|
// Expression
|
|
aQuotaManager.GetOriginMetadata(&aOriginDir)
|
|
.map([](auto metadata) -> Maybe<OriginMetadata> {
|
|
return Some(std::move(metadata));
|
|
}),
|
|
// Predicate.
|
|
IsSpecificError<NS_ERROR_MALFORMED_URI>,
|
|
// Fallback.
|
|
ErrToDefaultOk<Maybe<OriginMetadata>>));
|
|
|
|
if (!maybeMetadata) {
|
|
// Unknown directories during listing are allowed. Just warn if we find
|
|
// them.
|
|
QM_TRY_INSPECT(const auto& leafName,
|
|
MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, aOriginDir,
|
|
GetLeafName));
|
|
|
|
UNKNOWN_FILE_WARNING(leafName);
|
|
return NS_OK;
|
|
}
|
|
|
|
auto metadata = maybeMetadata.extract();
|
|
|
|
if (aQuotaManager.IsOriginInternal(metadata.mOrigin)) {
|
|
return NS_OK;
|
|
}
|
|
|
|
mOrigins.AppendElement(std::move(metadata.mOrigin));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void ListOriginsOp::GetResponse(RequestResponse& aResponse) {
|
|
AssertIsOnOwningThread();
|
|
|
|
aResponse = ListOriginsResponse();
|
|
if (mOrigins.IsEmpty()) {
|
|
return;
|
|
}
|
|
|
|
nsTArray<nsCString>& origins = aResponse.get_ListOriginsResponse().origins();
|
|
mOrigins.SwapElements(origins);
|
|
}
|
|
|
|
void ListOriginsOp::CloseDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
SafeDropDirectoryLock(mDirectoryLock);
|
|
}
|
|
|
|
} // namespace mozilla::dom::quota
|