mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
44c9b8c170
The planned group (eTLD+1 domain) support in OriginScope will require access to the group of a particular origin. PrincipalMetadata will not only allow easy access to the group, but it will also allow further DirectoryLockImpl cleanup. Differential Revision: https://phabricator.services.mozilla.com/D196034
3558 lines
112 KiB
C++
3558 lines
112 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 PersistentStorageInitializedOp final : public InitializedRequestBase {
|
|
public:
|
|
explicit PersistentStorageInitializedOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
|
|
: InitializedRequestBase(std::move(aQuotaManager),
|
|
"dom::quota::PersistentStorageInitializedOp") {}
|
|
|
|
private:
|
|
~PersistentStorageInitializedOp() = default;
|
|
|
|
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
|
|
|
|
bool GetResolveValue() override;
|
|
};
|
|
|
|
class TemporaryStorageInitializedOp final : public InitializedRequestBase {
|
|
public:
|
|
explicit TemporaryStorageInitializedOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
|
|
: InitializedRequestBase(std::move(aQuotaManager),
|
|
"dom::quota::TemporaryStorageInitializedOp") {}
|
|
|
|
private:
|
|
~TemporaryStorageInitializedOp() = default;
|
|
|
|
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
|
|
|
|
bool 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 InitializePersistentStorageOp final
|
|
: public ResolvableNormalOriginOp<bool> {
|
|
RefPtr<UniversalDirectoryLock> mDirectoryLock;
|
|
|
|
public:
|
|
InitializePersistentStorageOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
RefPtr<UniversalDirectoryLock> aDirectoryLock);
|
|
|
|
private:
|
|
~InitializePersistentStorageOp() = default;
|
|
|
|
RefPtr<BoolPromise> OpenDirectory() override;
|
|
|
|
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
|
|
|
|
bool 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 PrincipalInfo mPrincipalInfo;
|
|
PrincipalMetadata mPrincipalMetadata;
|
|
const PersistenceScope mPersistenceScope;
|
|
|
|
public:
|
|
ClearStoragesForOriginPrefixOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
const Maybe<PersistenceType>& aPersistenceType,
|
|
const PrincipalInfo& aPrincipalInfo);
|
|
|
|
private:
|
|
~ClearStoragesForOriginPrefixOp() = default;
|
|
|
|
nsresult DoInit(QuotaManager& aQuotaManager) override;
|
|
|
|
RefPtr<BoolPromise> OpenDirectory() override;
|
|
|
|
nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
|
|
|
|
OriginMetadataArray 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>> CreatePersistentStorageInitializedOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
|
|
return MakeRefPtr<PersistentStorageInitializedOp>(std::move(aQuotaManager));
|
|
}
|
|
|
|
RefPtr<ResolvableNormalOriginOp<bool>> CreateTemporaryStorageInitializedOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
|
|
return MakeRefPtr<TemporaryStorageInitializedOp>(std::move(aQuotaManager));
|
|
}
|
|
|
|
RefPtr<ResolvableNormalOriginOp<bool>> 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>> CreateInitializePersistentStorageOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
RefPtr<UniversalDirectoryLock> aDirectoryLock) {
|
|
return MakeRefPtr<InitializePersistentStorageOp>(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), 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),
|
|
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 PersistentStorageInitializedOp::DoDirectoryWork(
|
|
QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
AUTO_PROFILER_LABEL("PersistentStorageInitializedOp::DoDirectoryWork", OTHER);
|
|
|
|
mInitialized = aQuotaManager.IsPersistentStorageInitializedInternal();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool PersistentStorageInitializedOp::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);
|
|
}
|
|
|
|
InitializePersistentStorageOp::InitializePersistentStorageOp(
|
|
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
|
|
RefPtr<UniversalDirectoryLock> aDirectoryLock)
|
|
: ResolvableNormalOriginOp(std::move(aQuotaManager),
|
|
"dom::quota::InitializePersistentStorageOp"),
|
|
mDirectoryLock(std::move(aDirectoryLock)) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
RefPtr<BoolPromise> InitializePersistentStorageOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mDirectoryLock);
|
|
|
|
return BoolPromise::CreateAndResolve(true, __func__);
|
|
}
|
|
|
|
nsresult InitializePersistentStorageOp::DoDirectoryWork(
|
|
QuotaManager& aQuotaManager) {
|
|
AssertIsOnIOThread();
|
|
|
|
AUTO_PROFILER_LABEL("InitializePersistentStorageOp::DoDirectoryWork", OTHER);
|
|
|
|
QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
|
|
NS_ERROR_NOT_INITIALIZED);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(
|
|
aQuotaManager.EnsurePersistentStorageIsInitializedInternal()));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool InitializePersistentStorageOp::GetResolveValue() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return true;
|
|
}
|
|
|
|
void InitializePersistentStorageOp::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),
|
|
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), 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), 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),
|
|
[&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))) {
|
|
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))) {
|
|
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),
|
|
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),
|
|
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),
|
|
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"),
|
|
mPrincipalInfo(aPrincipalInfo),
|
|
mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
|
|
*aPersistenceType)
|
|
: PersistenceScope::CreateFromNull()) {
|
|
AssertIsOnOwningThread();
|
|
}
|
|
|
|
nsresult ClearStoragesForOriginPrefixOp::DoInit(QuotaManager& aQuotaManager) {
|
|
AssertIsOnOwningThread();
|
|
|
|
QM_TRY_UNWRAP(
|
|
mPrincipalMetadata,
|
|
aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
|
|
|
|
mPrincipalMetadata.AssertInvariants();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<BoolPromise> ClearStoragesForOriginPrefixOp::OpenDirectory() {
|
|
AssertIsOnOwningThread();
|
|
|
|
return OpenStorageDirectory(
|
|
mPersistenceScope, OriginScope::FromPrefix(mPrincipalMetadata),
|
|
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(mPrincipalMetadata));
|
|
}
|
|
} else {
|
|
MOZ_ASSERT(mPersistenceScope.IsValue());
|
|
|
|
DeleteFiles(aQuotaManager, mPersistenceScope.GetValue(),
|
|
OriginScope::FromPrefix(mPrincipalMetadata));
|
|
}
|
|
|
|
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),
|
|
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),
|
|
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), 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), 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
|