Backed out changeset f594e6f00208 (bug 1940883) for causing crashes in bug 1941164.
[gecko.git] / dom / quota / OriginOperations.cpp
blob6c997a13ce20bad0a0effda433ea5ad70dfd7fd2
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "OriginOperations.h"
9 #include <algorithm>
10 #include <cstdint>
11 #include <utility>
13 #include "ErrorList.h"
14 #include "FileUtils.h"
15 #include "GroupInfo.h"
16 #include "MainThreadUtils.h"
17 #include "mozilla/Assertions.h"
18 #include "mozilla/Atomics.h"
19 #include "mozilla/Maybe.h"
20 #include "mozilla/NotNull.h"
21 #include "mozilla/ProfilerLabels.h"
22 #include "mozilla/RefPtr.h"
23 #include "mozilla/Result.h"
24 #include "mozilla/ResultExtensions.h"
25 #include "mozilla/dom/Nullable.h"
26 #include "mozilla/dom/quota/CommonMetadata.h"
27 #include "mozilla/dom/quota/Client.h"
28 #include "mozilla/dom/quota/Constants.h"
29 #include "mozilla/dom/quota/DirectoryLock.h"
30 #include "mozilla/dom/quota/DirectoryLockInlines.h"
31 #include "mozilla/dom/quota/OriginDirectoryLock.h"
32 #include "mozilla/dom/quota/PersistenceType.h"
33 #include "mozilla/dom/quota/PrincipalUtils.h"
34 #include "mozilla/dom/quota/PQuota.h"
35 #include "mozilla/dom/quota/PQuotaRequest.h"
36 #include "mozilla/dom/quota/PQuotaUsageRequest.h"
37 #include "mozilla/dom/quota/OriginScope.h"
38 #include "mozilla/dom/quota/PersistenceScope.h"
39 #include "mozilla/dom/quota/QuotaCommon.h"
40 #include "mozilla/dom/quota/QuotaManager.h"
41 #include "mozilla/dom/quota/QuotaManagerImpl.h"
42 #include "mozilla/dom/quota/ResultExtensions.h"
43 #include "mozilla/dom/quota/StreamUtils.h"
44 #include "mozilla/dom/quota/UniversalDirectoryLock.h"
45 #include "mozilla/dom/quota/UsageInfo.h"
46 #include "mozilla/fallible.h"
47 #include "mozilla/ipc/BackgroundParent.h"
48 #include "mozilla/ipc/PBackgroundSharedTypes.h"
49 #include "NormalOriginOperationBase.h"
50 #include "nsCOMPtr.h"
51 #include "nsTHashMap.h"
52 #include "nsDebug.h"
53 #include "nsError.h"
54 #include "nsHashKeys.h"
55 #include "nsIBinaryOutputStream.h"
56 #include "nsIFile.h"
57 #include "nsIObjectOutputStream.h"
58 #include "nsIOutputStream.h"
59 #include "nsLiteralString.h"
60 #include "nsPrintfCString.h"
61 #include "nsString.h"
62 #include "nsTArray.h"
63 #include "OriginInfo.h"
64 #include "OriginOperationBase.h"
65 #include "OriginParser.h"
66 #include "QuotaRequestBase.h"
67 #include "ResolvableNormalOriginOp.h"
68 #include "prthread.h"
69 #include "prtime.h"
71 namespace mozilla::dom::quota {
73 using namespace mozilla::ipc;
75 template <class Base>
76 class OpenStorageDirectoryHelper : public Base {
77 protected:
78 OpenStorageDirectoryHelper(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
79 const char* aName)
80 : Base(std::move(aQuotaManager), aName) {}
82 RefPtr<BoolPromise> OpenStorageDirectory(
83 const PersistenceScope& aPersistenceScope,
84 const OriginScope& aOriginScope,
85 const Nullable<Client::Type>& aClientType, bool aExclusive,
86 bool aInitializeOrigins = false,
87 DirectoryLockCategory aCategory = DirectoryLockCategory::None);
89 RefPtr<UniversalDirectoryLock> mDirectoryLock;
92 class FinalizeOriginEvictionOp : public OriginOperationBase {
93 nsTArray<RefPtr<OriginDirectoryLock>> mLocks;
95 public:
96 FinalizeOriginEvictionOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
97 nsTArray<RefPtr<OriginDirectoryLock>>&& aLocks)
98 : OriginOperationBase(std::move(aQuotaManager),
99 "dom::quota::FinalizeOriginEvictionOp"),
100 mLocks(std::move(aLocks)) {
101 AssertIsOnOwningThread();
104 NS_INLINE_DECL_REFCOUNTING(FinalizeOriginEvictionOp, override)
106 private:
107 ~FinalizeOriginEvictionOp() = default;
109 virtual RefPtr<BoolPromise> Open() override;
111 virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
113 virtual void UnblockOpen() override;
116 class SaveOriginAccessTimeOp
117 : public OpenStorageDirectoryHelper<NormalOriginOperationBase> {
118 const OriginMetadata mOriginMetadata;
119 int64_t mTimestamp;
121 public:
122 SaveOriginAccessTimeOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
123 const OriginMetadata& aOriginMetadata,
124 int64_t aTimestamp)
125 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
126 "dom::quota::SaveOriginAccessTimeOp"),
127 mOriginMetadata(aOriginMetadata),
128 mTimestamp(aTimestamp) {
129 AssertIsOnOwningThread();
132 NS_INLINE_DECL_REFCOUNTING(SaveOriginAccessTimeOp, override)
134 private:
135 ~SaveOriginAccessTimeOp() = default;
137 RefPtr<BoolPromise> OpenDirectory() override;
139 virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
141 virtual void SendResults() override;
143 void CloseDirectory() override;
146 class ClearPrivateRepositoryOp
147 : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<bool>> {
148 public:
149 explicit ClearPrivateRepositoryOp(
150 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
151 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
152 "dom::quota::ClearPrivateRepositoryOp") {
153 AssertIsOnOwningThread();
156 private:
157 ~ClearPrivateRepositoryOp() = default;
159 RefPtr<BoolPromise> OpenDirectory() override;
161 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
163 bool UnwrapResolveValue() override { return true; }
165 void CloseDirectory() override;
168 class ShutdownStorageOp : public ResolvableNormalOriginOp<bool> {
169 RefPtr<UniversalDirectoryLock> mDirectoryLock;
171 public:
172 explicit ShutdownStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
173 : ResolvableNormalOriginOp(std::move(aQuotaManager),
174 "dom::quota::ShutdownStorageOp") {
175 AssertIsOnOwningThread();
178 private:
179 ~ShutdownStorageOp() = default;
181 #ifdef DEBUG
182 nsresult DirectoryOpen() override;
183 #endif
185 RefPtr<BoolPromise> OpenDirectory() override;
187 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
189 bool UnwrapResolveValue() override { return true; }
191 void CloseDirectory() override;
194 class CancelableHelper {
195 protected:
196 virtual const Atomic<bool>& GetIsCanceledFlag() = 0;
199 // A mix-in class to simplify operations that need to process every origin in
200 // one or more repositories. Sub-classes should call TraverseRepository in their
201 // DoDirectoryWork and implement a ProcessOrigin method for their per-origin
202 // logic.
203 class TraverseRepositoryHelper : public CancelableHelper {
204 public:
205 TraverseRepositoryHelper() = default;
207 protected:
208 virtual ~TraverseRepositoryHelper() = default;
210 // If ProcessOrigin returns an error, TraverseRepository will immediately
211 // terminate and return the received error code to its caller.
212 nsresult TraverseRepository(QuotaManager& aQuotaManager,
213 PersistenceType aPersistenceType);
215 private:
216 virtual nsresult ProcessOrigin(QuotaManager& aQuotaManager,
217 nsIFile& aOriginDir, const bool aPersistent,
218 const PersistenceType aPersistenceType) = 0;
221 class OriginUsageHelper : public CancelableHelper {
222 protected:
223 mozilla::Result<UsageInfo, nsresult> GetUsageForOrigin(
224 QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
225 const OriginMetadata& aOriginMetadata);
227 private:
228 mozilla::Result<UsageInfo, nsresult> GetUsageForOriginEntries(
229 QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
230 const OriginMetadata& aOriginMetadata, nsIFile& aDirectory,
231 bool aInitialized);
234 class GetUsageOp final
235 : public OpenStorageDirectoryHelper<
236 ResolvableNormalOriginOp<OriginUsageMetadataArray, true>>,
237 public TraverseRepositoryHelper,
238 public OriginUsageHelper {
239 OriginUsageMetadataArray mOriginUsages;
240 nsTHashMap<nsCStringHashKey, uint32_t> mOriginUsagesIndex;
242 bool mGetAll;
244 public:
245 GetUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, bool aGetAll);
247 private:
248 ~GetUsageOp() = default;
250 void ProcessOriginInternal(QuotaManager* aQuotaManager,
251 const PersistenceType aPersistenceType,
252 const nsACString& aOrigin,
253 const int64_t aTimestamp, const bool aPersisted,
254 const uint64_t aUsage);
256 RefPtr<BoolPromise> OpenDirectory() override;
258 const Atomic<bool>& GetIsCanceledFlag() override;
260 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
262 nsresult ProcessOrigin(QuotaManager& aQuotaManager, nsIFile& aOriginDir,
263 const bool aPersistent,
264 const PersistenceType aPersistenceType) override;
266 OriginUsageMetadataArray UnwrapResolveValue() override;
268 void CloseDirectory() override;
271 class GetOriginUsageOp final
272 : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<UsageInfo>>,
273 public OriginUsageHelper {
274 const PrincipalInfo mPrincipalInfo;
275 PrincipalMetadata mPrincipalMetadata;
276 UsageInfo mUsageInfo;
278 public:
279 GetOriginUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
280 const PrincipalInfo& aPrincipalInfo);
282 private:
283 ~GetOriginUsageOp() = default;
285 nsresult DoInit(QuotaManager& aQuotaManager) override;
287 RefPtr<BoolPromise> OpenDirectory() override;
289 virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
291 const Atomic<bool>& GetIsCanceledFlag() override;
293 UsageInfo UnwrapResolveValue() override;
295 void CloseDirectory() override;
298 class StorageNameOp final : public QuotaRequestBase {
299 nsString mName;
301 public:
302 explicit StorageNameOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
304 private:
305 ~StorageNameOp() = default;
307 RefPtr<BoolPromise> OpenDirectory() override;
309 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
311 void GetResponse(RequestResponse& aResponse) override;
313 void CloseDirectory() override;
316 class InitializedRequestBase : public ResolvableNormalOriginOp<bool> {
317 protected:
318 bool mInitialized;
320 InitializedRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
321 const char* aName);
323 private:
324 RefPtr<BoolPromise> OpenDirectory() override;
326 void CloseDirectory() override;
329 class StorageInitializedOp final : public InitializedRequestBase {
330 public:
331 explicit StorageInitializedOp(
332 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
333 : InitializedRequestBase(std::move(aQuotaManager),
334 "dom::quota::StorageInitializedOp") {}
336 private:
337 ~StorageInitializedOp() = default;
339 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
341 bool UnwrapResolveValue() override;
344 class PersistentStorageInitializedOp final : public InitializedRequestBase {
345 public:
346 explicit PersistentStorageInitializedOp(
347 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
348 : InitializedRequestBase(std::move(aQuotaManager),
349 "dom::quota::PersistentStorageInitializedOp") {}
351 private:
352 ~PersistentStorageInitializedOp() = default;
354 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
356 bool UnwrapResolveValue() override;
359 class TemporaryStorageInitializedOp final : public InitializedRequestBase {
360 public:
361 explicit TemporaryStorageInitializedOp(
362 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
363 : InitializedRequestBase(std::move(aQuotaManager),
364 "dom::quota::TemporaryStorageInitializedOp") {}
366 private:
367 ~TemporaryStorageInitializedOp() = default;
369 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
371 bool UnwrapResolveValue() override;
374 class TemporaryGroupInitializedOp final
375 : public ResolvableNormalOriginOp<bool> {
376 const PrincipalMetadata mPrincipalMetadata;
377 bool mInitialized;
379 public:
380 explicit TemporaryGroupInitializedOp(
381 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
382 const PrincipalMetadata& aPrincipalMetadata);
384 private:
385 ~TemporaryGroupInitializedOp() = default;
387 RefPtr<BoolPromise> OpenDirectory() override;
389 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
391 bool UnwrapResolveValue() override;
393 void CloseDirectory() override;
396 class InitializedOriginRequestBase : public ResolvableNormalOriginOp<bool> {
397 protected:
398 const PrincipalMetadata mPrincipalMetadata;
399 bool mInitialized;
401 InitializedOriginRequestBase(
402 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
403 const PrincipalMetadata& aPrincipalMetadata);
405 private:
406 RefPtr<BoolPromise> OpenDirectory() override;
408 void CloseDirectory() override;
411 class PersistentOriginInitializedOp final
412 : public InitializedOriginRequestBase {
413 public:
414 explicit PersistentOriginInitializedOp(
415 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
416 const OriginMetadata& aOriginMetadata);
418 private:
419 ~PersistentOriginInitializedOp() = default;
421 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
423 bool UnwrapResolveValue() override;
426 class TemporaryOriginInitializedOp final : public InitializedOriginRequestBase {
427 const PersistenceType mPersistenceType;
429 public:
430 explicit TemporaryOriginInitializedOp(
431 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
432 const OriginMetadata& aOriginMetadata);
434 private:
435 ~TemporaryOriginInitializedOp() = default;
437 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
439 bool UnwrapResolveValue() override;
442 class InitOp final : public ResolvableNormalOriginOp<bool> {
443 RefPtr<UniversalDirectoryLock> mDirectoryLock;
445 public:
446 InitOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
447 RefPtr<UniversalDirectoryLock> aDirectoryLock);
449 private:
450 ~InitOp() = default;
452 RefPtr<BoolPromise> OpenDirectory() override;
454 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
456 bool UnwrapResolveValue() override;
458 void CloseDirectory() override;
461 class InitializePersistentStorageOp final
462 : public ResolvableNormalOriginOp<bool> {
463 RefPtr<UniversalDirectoryLock> mDirectoryLock;
465 public:
466 InitializePersistentStorageOp(
467 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
468 RefPtr<UniversalDirectoryLock> aDirectoryLock);
470 private:
471 ~InitializePersistentStorageOp() = default;
473 RefPtr<BoolPromise> OpenDirectory() override;
475 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
477 bool UnwrapResolveValue() override;
479 void CloseDirectory() override;
482 class InitTemporaryStorageOp final
483 : public ResolvableNormalOriginOp<MaybePrincipalMetadataArray, true> {
484 MaybePrincipalMetadataArray mAllTemporaryGroups;
485 RefPtr<UniversalDirectoryLock> mDirectoryLock;
487 public:
488 InitTemporaryStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
489 RefPtr<UniversalDirectoryLock> aDirectoryLock);
491 private:
492 ~InitTemporaryStorageOp() = default;
494 RefPtr<BoolPromise> OpenDirectory() override;
496 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
498 MaybePrincipalMetadataArray UnwrapResolveValue() override;
500 void CloseDirectory() override;
503 class InitializeTemporaryGroupOp final : public ResolvableNormalOriginOp<bool> {
504 const PrincipalMetadata mPrincipalMetadata;
505 RefPtr<UniversalDirectoryLock> mDirectoryLock;
507 public:
508 InitializeTemporaryGroupOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
509 const PrincipalMetadata& aPrincipalMetadata,
510 RefPtr<UniversalDirectoryLock> aDirectoryLock);
512 private:
513 ~InitializeTemporaryGroupOp() = default;
515 RefPtr<BoolPromise> OpenDirectory() override;
517 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
519 bool UnwrapResolveValue() override;
521 void CloseDirectory() override;
524 class InitializeOriginRequestBase : public ResolvableNormalOriginOp<bool> {
525 protected:
526 const PrincipalMetadata mPrincipalMetadata;
527 RefPtr<UniversalDirectoryLock> mDirectoryLock;
528 bool mCreated;
530 InitializeOriginRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
531 const char* aName,
532 const PrincipalMetadata& aPrincipalMetadata,
533 RefPtr<UniversalDirectoryLock> aDirectoryLock);
535 private:
536 RefPtr<BoolPromise> OpenDirectory() override;
538 void CloseDirectory() override;
541 class InitializePersistentOriginOp final : public InitializeOriginRequestBase {
542 public:
543 InitializePersistentOriginOp(
544 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
545 const OriginMetadata& aOriginMetadata,
546 RefPtr<UniversalDirectoryLock> aDirectoryLock);
548 private:
549 ~InitializePersistentOriginOp() = default;
551 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
553 bool UnwrapResolveValue() override;
556 class InitializeTemporaryOriginOp final : public InitializeOriginRequestBase {
557 const PersistenceType mPersistenceType;
558 const bool mCreateIfNonExistent;
560 public:
561 InitializeTemporaryOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
562 const OriginMetadata& aOriginMetadata,
563 bool aCreateIfNonExistent,
564 RefPtr<UniversalDirectoryLock> aDirectoryLock);
566 private:
567 ~InitializeTemporaryOriginOp() = default;
569 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
571 bool UnwrapResolveValue() override;
574 class InitializeClientBase : public ResolvableNormalOriginOp<bool> {
575 protected:
576 const PrincipalInfo mPrincipalInfo;
577 ClientMetadata mClientMetadata;
578 RefPtr<UniversalDirectoryLock> mDirectoryLock;
579 const PersistenceType mPersistenceType;
580 const Client::Type mClientType;
581 bool mCreated;
583 InitializeClientBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
584 const char* aName, PersistenceType aPersistenceType,
585 const PrincipalInfo& aPrincipalInfo,
586 Client::Type aClientType);
588 nsresult DoInit(QuotaManager& aQuotaManager) override;
590 private:
591 RefPtr<BoolPromise> OpenDirectory() override;
593 void CloseDirectory() override;
596 class InitializePersistentClientOp : public InitializeClientBase {
597 public:
598 InitializePersistentClientOp(
599 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
600 const PrincipalInfo& aPrincipalInfo, Client::Type aClientType);
602 private:
603 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
605 bool UnwrapResolveValue() override;
608 class InitializeTemporaryClientOp : public InitializeClientBase {
609 public:
610 InitializeTemporaryClientOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
611 PersistenceType aPersistenceType,
612 const PrincipalInfo& aPrincipalInfo,
613 Client::Type aClientType);
615 private:
616 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
618 bool UnwrapResolveValue() override;
621 class GetFullOriginMetadataOp
622 : public OpenStorageDirectoryHelper<QuotaRequestBase> {
623 const GetFullOriginMetadataParams mParams;
624 // XXX Consider wrapping with LazyInitializedOnce
625 OriginMetadata mOriginMetadata;
626 Maybe<FullOriginMetadata> mMaybeFullOriginMetadata;
628 public:
629 GetFullOriginMetadataOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
630 const GetFullOriginMetadataParams& aParams);
632 private:
633 nsresult DoInit(QuotaManager& aQuotaManager) override;
635 RefPtr<BoolPromise> OpenDirectory() override;
637 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
639 void GetResponse(RequestResponse& aResponse) override;
641 void CloseDirectory() override;
644 class GetCachedOriginUsageOp
645 : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<uint64_t>> {
646 const PrincipalInfo mPrincipalInfo;
647 PrincipalMetadata mPrincipalMetadata;
648 uint64_t mUsage;
650 public:
651 GetCachedOriginUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
652 const PrincipalInfo& aPrincipalInfo);
654 private:
655 ~GetCachedOriginUsageOp() = default;
657 nsresult DoInit(QuotaManager& aQuotaManager) override;
659 RefPtr<BoolPromise> OpenDirectory() override;
661 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
663 uint64_t UnwrapResolveValue() override;
665 void CloseDirectory() override;
668 class ListCachedOriginsOp final
669 : public OpenStorageDirectoryHelper<
670 ResolvableNormalOriginOp<CStringArray, /* IsExclusive */ true>> {
671 nsTArray<nsCString> mOrigins;
673 public:
674 explicit ListCachedOriginsOp(
675 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
677 private:
678 ~ListCachedOriginsOp() = default;
680 RefPtr<BoolPromise> OpenDirectory() override;
682 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
684 CStringArray UnwrapResolveValue() override;
686 void CloseDirectory() override;
689 class ClearStorageOp final
690 : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<bool>> {
691 public:
692 explicit ClearStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
694 private:
695 ~ClearStorageOp() = default;
697 void DeleteFiles(QuotaManager& aQuotaManager);
699 void DeleteStorageFile(QuotaManager& aQuotaManager);
701 RefPtr<BoolPromise> OpenDirectory() override;
703 virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
705 bool UnwrapResolveValue() override;
707 void CloseDirectory() override;
710 class ClearRequestBase
711 : public OpenStorageDirectoryHelper<
712 ResolvableNormalOriginOp<OriginMetadataArray, true>> {
713 Atomic<uint64_t> mIterations;
715 protected:
716 OriginMetadataArray mOriginMetadataArray;
718 ClearRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
719 const char* aName)
720 : OpenStorageDirectoryHelper(std::move(aQuotaManager), aName),
721 mIterations(0) {
722 AssertIsOnOwningThread();
725 void DeleteFiles(QuotaManager& aQuotaManager,
726 const OriginMetadata& aOriginMetadata);
728 void DeleteFiles(QuotaManager& aQuotaManager,
729 PersistenceType aPersistenceType,
730 const OriginScope& aOriginScope);
732 private:
733 template <typename FileCollector>
734 void DeleteFilesInternal(QuotaManager& aQuotaManager,
735 PersistenceType aPersistenceType,
736 const OriginScope& aOriginScope,
737 const FileCollector& aFileCollector);
739 void DoStringify(nsACString& aData) override {
740 aData.Append("ClearRequestBase "_ns +
742 kStringifyStartInstance +
744 "Iterations:"_ns +
745 IntToCString(static_cast<uint64_t>(mIterations)) +
747 kStringifyEndInstance);
751 class ClearOriginOp final : public ClearRequestBase {
752 const PrincipalInfo mPrincipalInfo;
753 PrincipalMetadata mPrincipalMetadata;
754 const PersistenceScope mPersistenceScope;
756 public:
757 ClearOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
758 const mozilla::Maybe<PersistenceType>& aPersistenceType,
759 const PrincipalInfo& aPrincipalInfo);
761 private:
762 ~ClearOriginOp() = default;
764 nsresult DoInit(QuotaManager& aQuotaManager) override;
766 RefPtr<BoolPromise> OpenDirectory() override;
768 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
770 OriginMetadataArray UnwrapResolveValue() override;
772 void CloseDirectory() override;
775 class ClearClientOp final
776 : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<bool>> {
777 const PrincipalInfo mPrincipalInfo;
778 PrincipalMetadata mPrincipalMetadata;
779 const PersistenceScope mPersistenceScope;
780 const Client::Type mClientType;
782 public:
783 ClearClientOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
784 mozilla::Maybe<PersistenceType> aPersistenceType,
785 const PrincipalInfo& aPrincipalInfo,
786 const Client::Type aClientType);
788 private:
789 ~ClearClientOp() = default;
791 nsresult DoInit(QuotaManager& aQuotaManager) override;
793 RefPtr<BoolPromise> OpenDirectory() override;
795 void DeleteFiles(const ClientMetadata& aClientMetadata);
797 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
799 bool UnwrapResolveValue() override;
801 void CloseDirectory() override;
804 class ClearStoragesForOriginPrefixOp final
805 : public OpenStorageDirectoryHelper<ClearRequestBase> {
806 const PrincipalInfo mPrincipalInfo;
807 PrincipalMetadata mPrincipalMetadata;
808 const PersistenceScope mPersistenceScope;
810 public:
811 ClearStoragesForOriginPrefixOp(
812 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
813 const Maybe<PersistenceType>& aPersistenceType,
814 const PrincipalInfo& aPrincipalInfo);
816 private:
817 ~ClearStoragesForOriginPrefixOp() = default;
819 nsresult DoInit(QuotaManager& aQuotaManager) override;
821 RefPtr<BoolPromise> OpenDirectory() override;
823 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
825 OriginMetadataArray UnwrapResolveValue() override;
827 void CloseDirectory() override;
830 class ClearDataOp final : public ClearRequestBase {
831 const OriginAttributesPattern mPattern;
833 public:
834 ClearDataOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
835 const OriginAttributesPattern& aPattern);
837 private:
838 ~ClearDataOp() = default;
840 RefPtr<BoolPromise> OpenDirectory() override;
842 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
844 OriginMetadataArray UnwrapResolveValue() override;
846 void CloseDirectory() override;
849 class ShutdownOriginOp final
850 : public ResolvableNormalOriginOp<OriginMetadataArray, true> {
851 const PrincipalInfo mPrincipalInfo;
852 PrincipalMetadata mPrincipalMetadata;
853 OriginMetadataArray mOriginMetadataArray;
854 RefPtr<UniversalDirectoryLock> mDirectoryLock;
855 const PersistenceScope mPersistenceScope;
857 public:
858 ShutdownOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
859 mozilla::Maybe<PersistenceType> aPersistenceType,
860 const PrincipalInfo& aPrincipalInfo);
862 private:
863 ~ShutdownOriginOp() = default;
865 nsresult DoInit(QuotaManager& aQuotaManager) override;
867 RefPtr<BoolPromise> OpenDirectory() override;
869 void CollectOriginMetadata(const OriginMetadata& aOriginMetadata);
871 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
873 OriginMetadataArray UnwrapResolveValue() override;
875 void CloseDirectory() override;
878 class ShutdownClientOp final : public ResolvableNormalOriginOp<bool> {
879 const PrincipalInfo mPrincipalInfo;
880 PrincipalMetadata mPrincipalMetadata;
881 RefPtr<UniversalDirectoryLock> mDirectoryLock;
882 const PersistenceScope mPersistenceScope;
883 const Client::Type mClientType;
885 public:
886 ShutdownClientOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
887 mozilla::Maybe<PersistenceType> aPersistenceType,
888 const PrincipalInfo& aPrincipalInfo,
889 const Client::Type aClientType);
891 private:
892 ~ShutdownClientOp() = default;
894 nsresult DoInit(QuotaManager& aQuotaManager) override;
896 RefPtr<BoolPromise> OpenDirectory() override;
898 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
900 bool UnwrapResolveValue() override;
902 void CloseDirectory() override;
905 class PersistRequestBase : public OpenStorageDirectoryHelper<QuotaRequestBase> {
906 const PrincipalInfo mPrincipalInfo;
908 protected:
909 PrincipalMetadata mPrincipalMetadata;
911 protected:
912 PersistRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
913 const PrincipalInfo& aPrincipalInfo);
915 nsresult DoInit(QuotaManager& aQuotaManager) override;
917 private:
918 RefPtr<BoolPromise> OpenDirectory() override;
920 void CloseDirectory() override;
923 class PersistedOp final : public PersistRequestBase {
924 bool mPersisted;
926 public:
927 PersistedOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
928 const RequestParams& aParams);
930 private:
931 ~PersistedOp() = default;
933 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
935 void GetResponse(RequestResponse& aResponse) override;
938 class PersistOp final : public PersistRequestBase {
939 public:
940 PersistOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
941 const RequestParams& aParams);
943 private:
944 ~PersistOp() = default;
946 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
948 void GetResponse(RequestResponse& aResponse) override;
951 class EstimateOp final : public OpenStorageDirectoryHelper<QuotaRequestBase> {
952 const EstimateParams mParams;
953 OriginMetadata mOriginMetadata;
954 std::pair<uint64_t, uint64_t> mUsageAndLimit;
956 public:
957 EstimateOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
958 const EstimateParams& aParams);
960 private:
961 ~EstimateOp() = default;
963 nsresult DoInit(QuotaManager& aQuotaManager) override;
965 RefPtr<BoolPromise> OpenDirectory() override;
967 virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
969 void GetResponse(RequestResponse& aResponse) override;
971 void CloseDirectory() override;
974 class ListOriginsOp final
975 : public OpenStorageDirectoryHelper<
976 ResolvableNormalOriginOp<CStringArray, /* IsExclusive */ true>>,
977 public TraverseRepositoryHelper {
978 // XXX Bug 1521541 will make each origin has it's own state.
979 nsTArray<nsCString> mOrigins;
981 public:
982 explicit ListOriginsOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
984 private:
985 ~ListOriginsOp() = default;
987 RefPtr<BoolPromise> OpenDirectory() override;
989 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
991 const Atomic<bool>& GetIsCanceledFlag() override;
993 nsresult ProcessOrigin(QuotaManager& aQuotaManager, nsIFile& aOriginDir,
994 const bool aPersistent,
995 const PersistenceType aPersistenceType) override;
997 CStringArray UnwrapResolveValue() override;
999 void CloseDirectory() override;
1002 RefPtr<OriginOperationBase> CreateFinalizeOriginEvictionOp(
1003 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1004 nsTArray<RefPtr<OriginDirectoryLock>>&& aLocks) {
1005 return MakeRefPtr<FinalizeOriginEvictionOp>(std::move(aQuotaManager),
1006 std::move(aLocks));
1009 RefPtr<NormalOriginOperationBase> CreateSaveOriginAccessTimeOp(
1010 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1011 const OriginMetadata& aOriginMetadata, int64_t aTimestamp) {
1012 return MakeRefPtr<SaveOriginAccessTimeOp>(std::move(aQuotaManager),
1013 aOriginMetadata, aTimestamp);
1016 RefPtr<ResolvableNormalOriginOp<bool>> CreateClearPrivateRepositoryOp(
1017 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
1018 return MakeRefPtr<ClearPrivateRepositoryOp>(std::move(aQuotaManager));
1021 RefPtr<ResolvableNormalOriginOp<bool>> CreateShutdownStorageOp(
1022 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
1023 return MakeRefPtr<ShutdownStorageOp>(std::move(aQuotaManager));
1026 RefPtr<ResolvableNormalOriginOp<OriginUsageMetadataArray, true>>
1027 CreateGetUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1028 bool aGetAll) {
1029 return MakeRefPtr<GetUsageOp>(std::move(aQuotaManager), aGetAll);
1032 RefPtr<ResolvableNormalOriginOp<UsageInfo>> CreateGetOriginUsageOp(
1033 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1034 const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
1035 return MakeRefPtr<GetOriginUsageOp>(std::move(aQuotaManager), aPrincipalInfo);
1038 RefPtr<QuotaRequestBase> CreateStorageNameOp(
1039 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
1040 return MakeRefPtr<StorageNameOp>(std::move(aQuotaManager));
1043 RefPtr<ResolvableNormalOriginOp<bool>> CreateStorageInitializedOp(
1044 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
1045 return MakeRefPtr<StorageInitializedOp>(std::move(aQuotaManager));
1048 RefPtr<ResolvableNormalOriginOp<bool>> CreatePersistentStorageInitializedOp(
1049 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
1050 return MakeRefPtr<PersistentStorageInitializedOp>(std::move(aQuotaManager));
1053 RefPtr<ResolvableNormalOriginOp<bool>> CreateTemporaryStorageInitializedOp(
1054 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
1055 return MakeRefPtr<TemporaryStorageInitializedOp>(std::move(aQuotaManager));
1058 RefPtr<ResolvableNormalOriginOp<bool>> CreateTemporaryGroupInitializedOp(
1059 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1060 const PrincipalMetadata& aPrincipalMetadata) {
1061 return MakeRefPtr<TemporaryGroupInitializedOp>(std::move(aQuotaManager),
1062 aPrincipalMetadata);
1065 RefPtr<ResolvableNormalOriginOp<bool>> CreatePersistentOriginInitializedOp(
1066 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1067 const OriginMetadata& aOriginMetadata) {
1068 return MakeRefPtr<PersistentOriginInitializedOp>(std::move(aQuotaManager),
1069 aOriginMetadata);
1072 RefPtr<ResolvableNormalOriginOp<bool>> CreateTemporaryOriginInitializedOp(
1073 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1074 const OriginMetadata& aOriginMetadata) {
1075 return MakeRefPtr<TemporaryOriginInitializedOp>(std::move(aQuotaManager),
1076 aOriginMetadata);
1079 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitOp(
1080 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1081 RefPtr<UniversalDirectoryLock> aDirectoryLock) {
1082 return MakeRefPtr<InitOp>(std::move(aQuotaManager),
1083 std::move(aDirectoryLock));
1086 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializePersistentStorageOp(
1087 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1088 RefPtr<UniversalDirectoryLock> aDirectoryLock) {
1089 return MakeRefPtr<InitializePersistentStorageOp>(std::move(aQuotaManager),
1090 std::move(aDirectoryLock));
1093 RefPtr<ResolvableNormalOriginOp<MaybePrincipalMetadataArray, true>>
1094 CreateInitTemporaryStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1095 RefPtr<UniversalDirectoryLock> aDirectoryLock) {
1096 return MakeRefPtr<InitTemporaryStorageOp>(std::move(aQuotaManager),
1097 std::move(aDirectoryLock));
1100 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializeTemporaryGroupOp(
1101 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1102 const PrincipalMetadata& aPrincipalMetadata,
1103 RefPtr<UniversalDirectoryLock> aDirectoryLock) {
1104 return MakeRefPtr<InitializeTemporaryGroupOp>(
1105 std::move(aQuotaManager), aPrincipalMetadata, std::move(aDirectoryLock));
1108 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializePersistentOriginOp(
1109 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1110 const OriginMetadata& aOriginMetadata,
1111 RefPtr<UniversalDirectoryLock> aDirectoryLock) {
1112 return MakeRefPtr<InitializePersistentOriginOp>(
1113 std::move(aQuotaManager), aOriginMetadata, std::move(aDirectoryLock));
1116 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializeTemporaryOriginOp(
1117 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1118 const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent,
1119 RefPtr<UniversalDirectoryLock> aDirectoryLock) {
1120 return MakeRefPtr<InitializeTemporaryOriginOp>(
1121 std::move(aQuotaManager), aOriginMetadata, aCreateIfNonExistent,
1122 std::move(aDirectoryLock));
1125 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializePersistentClientOp(
1126 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1127 const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
1128 const Client::Type aClientType) {
1129 return MakeRefPtr<InitializePersistentClientOp>(std::move(aQuotaManager),
1130 aPrincipalInfo, aClientType);
1133 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializeTemporaryClientOp(
1134 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1135 const PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
1136 const Client::Type aClientType) {
1137 return MakeRefPtr<InitializeTemporaryClientOp>(
1138 std::move(aQuotaManager), aPersistenceType, aPrincipalInfo, aClientType);
1141 RefPtr<QuotaRequestBase> CreateGetFullOriginMetadataOp(
1142 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1143 const GetFullOriginMetadataParams& aParams) {
1144 return MakeRefPtr<GetFullOriginMetadataOp>(std::move(aQuotaManager), aParams);
1147 RefPtr<ResolvableNormalOriginOp<uint64_t>> CreateGetCachedOriginUsageOp(
1148 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1149 const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
1150 return MakeRefPtr<GetCachedOriginUsageOp>(std::move(aQuotaManager),
1151 aPrincipalInfo);
1154 RefPtr<ResolvableNormalOriginOp<CStringArray, true>> CreateListCachedOriginsOp(
1155 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
1156 return MakeRefPtr<ListCachedOriginsOp>(std::move(aQuotaManager));
1159 RefPtr<ResolvableNormalOriginOp<bool>> CreateClearStorageOp(
1160 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
1161 return MakeRefPtr<ClearStorageOp>(std::move(aQuotaManager));
1164 RefPtr<ResolvableNormalOriginOp<OriginMetadataArray, true>> CreateClearOriginOp(
1165 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1166 const Maybe<PersistenceType>& aPersistenceType,
1167 const PrincipalInfo& aPrincipalInfo) {
1168 return MakeRefPtr<ClearOriginOp>(std::move(aQuotaManager), aPersistenceType,
1169 aPrincipalInfo);
1172 RefPtr<ResolvableNormalOriginOp<bool>> CreateClearClientOp(
1173 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1174 Maybe<PersistenceType> aPersistenceType,
1175 const PrincipalInfo& aPrincipalInfo, Client::Type aClientType) {
1176 return MakeRefPtr<ClearClientOp>(std::move(aQuotaManager), aPersistenceType,
1177 aPrincipalInfo, aClientType);
1180 RefPtr<ResolvableNormalOriginOp<OriginMetadataArray, true>>
1181 CreateClearStoragesForOriginPrefixOp(
1182 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1183 const Maybe<PersistenceType>& aPersistenceType,
1184 const PrincipalInfo& aPrincipalInfo) {
1185 return MakeRefPtr<ClearStoragesForOriginPrefixOp>(
1186 std::move(aQuotaManager), aPersistenceType, aPrincipalInfo);
1189 RefPtr<ResolvableNormalOriginOp<OriginMetadataArray, true>> CreateClearDataOp(
1190 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1191 const OriginAttributesPattern& aPattern) {
1192 return MakeRefPtr<ClearDataOp>(std::move(aQuotaManager), aPattern);
1195 RefPtr<ResolvableNormalOriginOp<OriginMetadataArray, true>>
1196 CreateShutdownOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1197 Maybe<PersistenceType> aPersistenceType,
1198 const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
1199 return MakeRefPtr<ShutdownOriginOp>(std::move(aQuotaManager),
1200 aPersistenceType, aPrincipalInfo);
1203 RefPtr<ResolvableNormalOriginOp<bool>> CreateShutdownClientOp(
1204 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1205 Maybe<PersistenceType> aPersistenceType,
1206 const PrincipalInfo& aPrincipalInfo, Client::Type aClientType) {
1207 return MakeRefPtr<ShutdownClientOp>(
1208 std::move(aQuotaManager), aPersistenceType, aPrincipalInfo, aClientType);
1211 RefPtr<QuotaRequestBase> CreatePersistedOp(
1212 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1213 const RequestParams& aParams) {
1214 return MakeRefPtr<PersistedOp>(std::move(aQuotaManager), aParams);
1217 RefPtr<QuotaRequestBase> CreatePersistOp(
1218 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1219 const RequestParams& aParams) {
1220 return MakeRefPtr<PersistOp>(std::move(aQuotaManager), aParams);
1223 RefPtr<QuotaRequestBase> CreateEstimateOp(
1224 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1225 const EstimateParams& aParams) {
1226 return MakeRefPtr<EstimateOp>(std::move(aQuotaManager), aParams);
1229 RefPtr<ResolvableNormalOriginOp<CStringArray, /* IsExclusive */ true>>
1230 CreateListOriginsOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
1231 return MakeRefPtr<ListOriginsOp>(std::move(aQuotaManager));
1234 template <class Base>
1235 RefPtr<BoolPromise> OpenStorageDirectoryHelper<Base>::OpenStorageDirectory(
1236 const PersistenceScope& aPersistenceScope, const OriginScope& aOriginScope,
1237 const Nullable<Client::Type>& aClientType, bool aExclusive,
1238 bool aInitializeOrigins, const DirectoryLockCategory aCategory) {
1239 return Base::mQuotaManager
1240 ->OpenStorageDirectory(aPersistenceScope, aOriginScope, aClientType,
1241 aExclusive, aInitializeOrigins, aCategory)
1242 ->Then(GetCurrentSerialEventTarget(), __func__,
1243 [self = RefPtr(this)](
1244 UniversalDirectoryLockPromise::ResolveOrRejectValue&& aValue) {
1245 if (aValue.IsReject()) {
1246 return BoolPromise::CreateAndReject(aValue.RejectValue(),
1247 __func__);
1250 self->mDirectoryLock = std::move(aValue.ResolveValue());
1252 return BoolPromise::CreateAndResolve(true, __func__);
1256 RefPtr<BoolPromise> FinalizeOriginEvictionOp::Open() {
1257 AssertIsOnOwningThread();
1258 MOZ_ASSERT(!mLocks.IsEmpty());
1260 return BoolPromise::CreateAndResolve(true, __func__);
1263 nsresult FinalizeOriginEvictionOp::DoDirectoryWork(
1264 QuotaManager& aQuotaManager) {
1265 AssertIsOnIOThread();
1267 AUTO_PROFILER_LABEL("FinalizeOriginEvictionOp::DoDirectoryWork", OTHER);
1269 for (const auto& lock : mLocks) {
1270 aQuotaManager.OriginClearCompleted(lock->OriginMetadata(),
1271 Nullable<Client::Type>());
1274 return NS_OK;
1277 void FinalizeOriginEvictionOp::UnblockOpen() {
1278 AssertIsOnOwningThread();
1280 nsTArray<OriginMetadata> origins;
1282 std::transform(mLocks.cbegin(), mLocks.cend(), MakeBackInserter(origins),
1283 [](const auto& lock) { return lock->OriginMetadata(); });
1285 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NS_NewRunnableFunction(
1286 "dom::quota::FinalizeOriginEvictionOp::UnblockOpen",
1287 [quotaManager = mQuotaManager, origins = std::move(origins)]() {
1288 quotaManager->NoteUninitializedOrigins(origins);
1289 })));
1291 for (const auto& lock : mLocks) {
1292 lock->Drop();
1294 mLocks.Clear();
1297 RefPtr<BoolPromise> SaveOriginAccessTimeOp::OpenDirectory() {
1298 AssertIsOnOwningThread();
1300 return OpenStorageDirectory(
1301 PersistenceScope::CreateFromValue(mOriginMetadata.mPersistenceType),
1302 OriginScope::FromOrigin(mOriginMetadata), Nullable<Client::Type>(),
1303 /* aExclusive */ false);
1306 nsresult SaveOriginAccessTimeOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1307 AssertIsOnIOThread();
1308 aQuotaManager.AssertStorageIsInitializedInternal();
1310 AUTO_PROFILER_LABEL("SaveOriginAccessTimeOp::DoDirectoryWork", OTHER);
1312 QM_TRY(MOZ_TO_RESULT(!QuotaManager::IsShuttingDown()), NS_ERROR_ABORT);
1314 QM_TRY_INSPECT(const auto& file,
1315 aQuotaManager.GetOriginDirectory(mOriginMetadata));
1317 // The origin directory might not exist
1318 // anymore, because it was deleted by a clear operation.
1319 QM_TRY_INSPECT(const bool& exists, MOZ_TO_RESULT_INVOKE_MEMBER(file, Exists));
1321 if (exists) {
1322 QM_TRY(MOZ_TO_RESULT(file->Append(nsLiteralString(METADATA_V2_FILE_NAME))));
1324 QM_TRY_INSPECT(const auto& stream,
1325 GetBinaryOutputStream(*file, FileFlag::Update));
1326 MOZ_ASSERT(stream);
1328 QM_TRY(MOZ_TO_RESULT(stream->Write64(mTimestamp)));
1331 return NS_OK;
1334 void SaveOriginAccessTimeOp::SendResults() {}
1336 void SaveOriginAccessTimeOp::CloseDirectory() {
1337 AssertIsOnOwningThread();
1339 SafeDropDirectoryLock(mDirectoryLock);
1342 RefPtr<BoolPromise> ClearPrivateRepositoryOp::OpenDirectory() {
1343 AssertIsOnOwningThread();
1345 return OpenStorageDirectory(
1346 PersistenceScope::CreateFromValue(PERSISTENCE_TYPE_PRIVATE),
1347 OriginScope::FromNull(), Nullable<Client::Type>(),
1348 /* aExclusive */ true, /* aInitializeOrigins */ false,
1349 DirectoryLockCategory::UninitOrigins);
1352 nsresult ClearPrivateRepositoryOp::DoDirectoryWork(
1353 QuotaManager& aQuotaManager) {
1354 AssertIsOnIOThread();
1355 aQuotaManager.AssertStorageIsInitializedInternal();
1357 AUTO_PROFILER_LABEL("ClearPrivateRepositoryOp::DoDirectoryWork", OTHER);
1359 QM_TRY_INSPECT(
1360 const auto& directory,
1361 QM_NewLocalFile(aQuotaManager.GetStoragePath(PERSISTENCE_TYPE_PRIVATE)));
1363 nsresult rv = directory->Remove(true);
1364 if (rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
1365 // This should never fail if we've closed all storage connections
1366 // correctly...
1367 MOZ_ASSERT(false, "Failed to remove directory!");
1370 aQuotaManager.RemoveQuotaForRepository(PERSISTENCE_TYPE_PRIVATE);
1372 aQuotaManager.RepositoryClearCompleted(PERSISTENCE_TYPE_PRIVATE);
1374 return NS_OK;
1377 void ClearPrivateRepositoryOp::CloseDirectory() {
1378 AssertIsOnOwningThread();
1380 SafeDropDirectoryLock(mDirectoryLock);
1383 RefPtr<BoolPromise> ShutdownStorageOp::OpenDirectory() {
1384 AssertIsOnOwningThread();
1386 // Clear directory lock tables (which also saves origin access time) before
1387 // acquiring the exclusive lock below. Otherwise, saving of origin access
1388 // time would be scheduled after storage shutdown and that would initialize
1389 // storage again in the end.
1390 mQuotaManager->ClearDirectoryLockTables();
1392 mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
1393 PersistenceScope::CreateFromNull(), OriginScope::FromNull(),
1394 Nullable<Client::Type>(),
1395 /* aExclusive */ true, DirectoryLockCategory::UninitStorage);
1397 return mDirectoryLock->Acquire();
1400 #ifdef DEBUG
1401 nsresult ShutdownStorageOp::DirectoryOpen() {
1402 AssertIsOnBackgroundThread();
1403 MOZ_ASSERT(mDirectoryLock);
1404 mDirectoryLock->AssertIsAcquiredExclusively();
1406 return NormalOriginOperationBase::DirectoryOpen();
1408 #endif
1410 nsresult ShutdownStorageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1411 AssertIsOnIOThread();
1413 AUTO_PROFILER_LABEL("ShutdownStorageOp::DoDirectoryWork", OTHER);
1415 aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
1416 "ShutdownStorageOp::DoDirectoryWork -> ShutdownStorageInternal."_ns);
1418 aQuotaManager.ShutdownStorageInternal();
1420 return NS_OK;
1423 void ShutdownStorageOp::CloseDirectory() {
1424 AssertIsOnOwningThread();
1426 DropDirectoryLockIfNotDropped(mDirectoryLock);
1429 nsresult TraverseRepositoryHelper::TraverseRepository(
1430 QuotaManager& aQuotaManager, PersistenceType aPersistenceType) {
1431 AssertIsOnIOThread();
1433 QM_TRY_INSPECT(
1434 const auto& directory,
1435 QM_NewLocalFile(aQuotaManager.GetStoragePath(aPersistenceType)));
1437 QM_TRY_INSPECT(const bool& exists,
1438 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
1440 if (!exists) {
1441 return NS_OK;
1444 QM_TRY(CollectEachFileAtomicCancelable(
1445 *directory, GetIsCanceledFlag(),
1446 [this, aPersistenceType, &aQuotaManager,
1447 persistent = aPersistenceType == PERSISTENCE_TYPE_PERSISTENT](
1448 const nsCOMPtr<nsIFile>& originDir) -> Result<Ok, nsresult> {
1449 QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*originDir));
1451 switch (dirEntryKind) {
1452 case nsIFileKind::ExistsAsDirectory:
1453 QM_TRY(MOZ_TO_RESULT(ProcessOrigin(aQuotaManager, *originDir,
1454 persistent, aPersistenceType)));
1455 break;
1457 case nsIFileKind::ExistsAsFile: {
1458 QM_TRY_INSPECT(const auto& leafName,
1459 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
1460 nsAutoString, originDir, GetLeafName));
1462 // Unknown files during getting usages are allowed. Just warn if we
1463 // find them.
1464 if (!IsOSMetadata(leafName)) {
1465 UNKNOWN_FILE_WARNING(leafName);
1468 break;
1471 case nsIFileKind::DoesNotExist:
1472 // Ignore files that got removed externally while iterating.
1473 break;
1476 return Ok{};
1477 }));
1479 return NS_OK;
1482 Result<UsageInfo, nsresult> OriginUsageHelper::GetUsageForOrigin(
1483 QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
1484 const OriginMetadata& aOriginMetadata) {
1485 AssertIsOnIOThread();
1486 MOZ_ASSERT(aOriginMetadata.mPersistenceType == aPersistenceType);
1488 QM_TRY_INSPECT(const auto& directory,
1489 aQuotaManager.GetOriginDirectory(aOriginMetadata));
1491 QM_TRY_INSPECT(const bool& exists,
1492 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
1494 if (!exists || GetIsCanceledFlag()) {
1495 return UsageInfo();
1498 // If the directory exists then enumerate all the files inside, adding up
1499 // the sizes to get the final usage statistic.
1500 bool initialized;
1502 if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
1503 initialized = aQuotaManager.IsPersistentOriginInitializedInternal(
1504 aOriginMetadata.mOrigin);
1505 } else {
1506 initialized = aQuotaManager.IsTemporaryStorageInitializedInternal();
1509 return GetUsageForOriginEntries(aQuotaManager, aPersistenceType,
1510 aOriginMetadata, *directory, initialized);
1513 Result<UsageInfo, nsresult> OriginUsageHelper::GetUsageForOriginEntries(
1514 QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
1515 const OriginMetadata& aOriginMetadata, nsIFile& aDirectory,
1516 const bool aInitialized) {
1517 AssertIsOnIOThread();
1519 QM_TRY_RETURN((ReduceEachFileAtomicCancelable(
1520 aDirectory, GetIsCanceledFlag(), UsageInfo{},
1521 [&](UsageInfo oldUsageInfo, const nsCOMPtr<nsIFile>& file)
1522 -> mozilla::Result<UsageInfo, nsresult> {
1523 QM_TRY_INSPECT(
1524 const auto& leafName,
1525 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, file, GetLeafName));
1527 QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*file));
1529 switch (dirEntryKind) {
1530 case nsIFileKind::ExistsAsDirectory: {
1531 Client::Type clientType;
1532 const bool ok =
1533 Client::TypeFromText(leafName, clientType, fallible);
1534 if (!ok) {
1535 // Unknown directories during getting usage for an origin (even
1536 // for an uninitialized origin) are now allowed. Just warn if we
1537 // find them.
1538 UNKNOWN_FILE_WARNING(leafName);
1539 break;
1542 Client* const client = aQuotaManager.GetClient(clientType);
1543 MOZ_ASSERT(client);
1545 QM_TRY_INSPECT(const auto& usageInfo,
1546 aInitialized ? client->GetUsageForOrigin(
1547 aPersistenceType, aOriginMetadata,
1548 GetIsCanceledFlag())
1549 : client->InitOrigin(
1550 aPersistenceType, aOriginMetadata,
1551 GetIsCanceledFlag()));
1552 return oldUsageInfo + usageInfo;
1555 case nsIFileKind::ExistsAsFile:
1556 // We are maintaining existing behavior for unknown files here (just
1557 // continuing).
1558 // This can possibly be used by developers to add temporary backups
1559 // into origin directories without losing get usage functionality.
1560 if (IsTempMetadata(leafName)) {
1561 if (!aInitialized) {
1562 QM_TRY(MOZ_TO_RESULT(file->Remove(/* recursive */ false)));
1565 break;
1568 if (IsOriginMetadata(leafName) || IsOSMetadata(leafName) ||
1569 IsDotFile(leafName)) {
1570 break;
1573 // Unknown files during getting usage for an origin (even for an
1574 // uninitialized origin) are now allowed. Just warn if we find them.
1575 UNKNOWN_FILE_WARNING(leafName);
1576 break;
1578 case nsIFileKind::DoesNotExist:
1579 // Ignore files that got removed externally while iterating.
1580 break;
1583 return oldUsageInfo;
1584 })));
1587 GetUsageOp::GetUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1588 bool aGetAll)
1589 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
1590 "dom::quota::GetUsageOp"),
1591 mGetAll(aGetAll) {
1592 AssertIsOnOwningThread();
1595 void GetUsageOp::ProcessOriginInternal(QuotaManager* aQuotaManager,
1596 const PersistenceType aPersistenceType,
1597 const nsACString& aOrigin,
1598 const int64_t aTimestamp,
1599 const bool aPersisted,
1600 const uint64_t aUsage) {
1601 if (!mGetAll && aQuotaManager->IsOriginInternal(aOrigin)) {
1602 return;
1605 // We can't store pointers to OriginUsage objects in the hashtable
1606 // since AppendElement() reallocates its internal array buffer as number
1607 // of elements grows.
1608 const auto& originUsage =
1609 mOriginUsagesIndex.WithEntryHandle(aOrigin, [&](auto&& entry) {
1610 if (entry) {
1611 return WrapNotNullUnchecked(&mOriginUsages[entry.Data()]);
1614 entry.Insert(mOriginUsages.Length());
1616 OriginUsageMetadata metadata;
1617 metadata.mOrigin = aOrigin;
1618 metadata.mPersistenceType = PERSISTENCE_TYPE_DEFAULT;
1619 metadata.mPersisted = false;
1620 metadata.mLastAccessTime = 0;
1621 metadata.mUsage = 0;
1623 return mOriginUsages.EmplaceBack(std::move(metadata));
1626 if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) {
1627 originUsage->mPersisted = aPersisted;
1630 originUsage->mUsage = originUsage->mUsage + aUsage;
1632 originUsage->mLastAccessTime =
1633 std::max<int64_t>(originUsage->mLastAccessTime, aTimestamp);
1636 const Atomic<bool>& GetUsageOp::GetIsCanceledFlag() {
1637 AssertIsOnIOThread();
1639 return Canceled();
1642 // XXX Remove aPersistent
1643 // XXX Remove aPersistenceType once GetUsageForOrigin uses the persistence
1644 // type from OriginMetadata
1645 nsresult GetUsageOp::ProcessOrigin(QuotaManager& aQuotaManager,
1646 nsIFile& aOriginDir, const bool aPersistent,
1647 const PersistenceType aPersistenceType) {
1648 AssertIsOnIOThread();
1650 QM_TRY_UNWRAP(auto maybeMetadata,
1651 QM_OR_ELSE_WARN_IF(
1652 // Expression
1653 aQuotaManager.LoadFullOriginMetadataWithRestore(&aOriginDir)
1654 .map([](auto metadata) -> Maybe<FullOriginMetadata> {
1655 return Some(std::move(metadata));
1657 // Predicate.
1658 IsSpecificError<NS_ERROR_MALFORMED_URI>,
1659 // Fallback.
1660 ErrToDefaultOk<Maybe<FullOriginMetadata>>));
1662 if (!maybeMetadata) {
1663 // Unknown directories during getting usage are allowed. Just warn if we
1664 // find them.
1665 QM_TRY_INSPECT(const auto& leafName,
1666 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, aOriginDir,
1667 GetLeafName));
1669 UNKNOWN_FILE_WARNING(leafName);
1670 return NS_OK;
1673 auto metadata = maybeMetadata.extract();
1675 QM_TRY_INSPECT(const auto& usageInfo,
1676 GetUsageForOrigin(aQuotaManager, aPersistenceType, metadata));
1678 ProcessOriginInternal(&aQuotaManager, aPersistenceType, metadata.mOrigin,
1679 metadata.mLastAccessTime, metadata.mPersisted,
1680 usageInfo.TotalUsage().valueOr(0));
1682 return NS_OK;
1685 RefPtr<BoolPromise> GetUsageOp::OpenDirectory() {
1686 AssertIsOnOwningThread();
1688 return OpenStorageDirectory(PersistenceScope::CreateFromNull(),
1689 OriginScope::FromNull(), Nullable<Client::Type>(),
1690 /* aExclusive */ false);
1693 nsresult GetUsageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1694 AssertIsOnIOThread();
1695 aQuotaManager.AssertStorageIsInitializedInternal();
1697 AUTO_PROFILER_LABEL("GetUsageOp::DoDirectoryWork", OTHER);
1699 nsresult rv;
1701 for (const PersistenceType type : kAllPersistenceTypes) {
1702 rv = TraverseRepository(aQuotaManager, type);
1703 if (NS_WARN_IF(NS_FAILED(rv))) {
1704 return rv;
1708 // TraverseRepository above only consulted the filesystem. We also need to
1709 // consider origins which may have pending quota usage, such as buffered
1710 // LocalStorage writes for an origin which didn't previously have any
1711 // LocalStorage data.
1713 aQuotaManager.CollectPendingOriginsForListing(
1714 [this, &aQuotaManager](const auto& originInfo) {
1715 ProcessOriginInternal(
1716 &aQuotaManager, originInfo->GetGroupInfo()->GetPersistenceType(),
1717 originInfo->Origin(), originInfo->LockedAccessTime(),
1718 originInfo->LockedPersisted(), originInfo->LockedUsage());
1721 return NS_OK;
1724 OriginUsageMetadataArray GetUsageOp::UnwrapResolveValue() {
1725 AssertIsOnOwningThread();
1727 return std::move(mOriginUsages);
1730 void GetUsageOp::CloseDirectory() {
1731 AssertIsOnOwningThread();
1733 SafeDropDirectoryLock(mDirectoryLock);
1736 GetOriginUsageOp::GetOriginUsageOp(
1737 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1738 const PrincipalInfo& aPrincipalInfo)
1739 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
1740 "dom::quota::GetOriginUsageOp"),
1741 mPrincipalInfo(aPrincipalInfo) {
1742 AssertIsOnOwningThread();
1745 nsresult GetOriginUsageOp::DoInit(QuotaManager& aQuotaManager) {
1746 AssertIsOnOwningThread();
1748 QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
1749 aQuotaManager, mPrincipalInfo));
1751 mPrincipalMetadata.AssertInvariants();
1753 return NS_OK;
1756 RefPtr<BoolPromise> GetOriginUsageOp::OpenDirectory() {
1757 AssertIsOnOwningThread();
1759 return OpenStorageDirectory(PersistenceScope::CreateFromNull(),
1760 OriginScope::FromOrigin(mPrincipalMetadata),
1761 Nullable<Client::Type>(),
1762 /* aExclusive */ false);
1765 const Atomic<bool>& GetOriginUsageOp::GetIsCanceledFlag() {
1766 AssertIsOnIOThread();
1768 return Canceled();
1771 nsresult GetOriginUsageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1772 AssertIsOnIOThread();
1773 aQuotaManager.AssertStorageIsInitializedInternal();
1774 MOZ_ASSERT(mUsageInfo.TotalUsage().isNothing());
1776 AUTO_PROFILER_LABEL("GetOriginUsageOp::DoDirectoryWork", OTHER);
1778 // Add all the persistent/temporary/default/private storage files we care
1779 // about.
1780 for (const PersistenceType type : kAllPersistenceTypes) {
1781 const OriginMetadata originMetadata = {mPrincipalMetadata, type};
1783 auto usageInfoOrErr =
1784 GetUsageForOrigin(aQuotaManager, type, originMetadata);
1785 if (NS_WARN_IF(usageInfoOrErr.isErr())) {
1786 return usageInfoOrErr.unwrapErr();
1789 mUsageInfo += usageInfoOrErr.unwrap();
1792 return NS_OK;
1795 UsageInfo GetOriginUsageOp::UnwrapResolveValue() {
1796 AssertIsOnOwningThread();
1798 return mUsageInfo;
1801 void GetOriginUsageOp::CloseDirectory() {
1802 AssertIsOnOwningThread();
1804 SafeDropDirectoryLock(mDirectoryLock);
1807 StorageNameOp::StorageNameOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
1808 : QuotaRequestBase(std::move(aQuotaManager), "dom::quota::StorageNameOp") {
1809 AssertIsOnOwningThread();
1812 RefPtr<BoolPromise> StorageNameOp::OpenDirectory() {
1813 AssertIsOnOwningThread();
1815 return BoolPromise::CreateAndResolve(true, __func__);
1818 nsresult StorageNameOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1819 AssertIsOnIOThread();
1821 AUTO_PROFILER_LABEL("StorageNameOp::DoDirectoryWork", OTHER);
1823 mName = aQuotaManager.GetStorageName();
1825 return NS_OK;
1828 void StorageNameOp::GetResponse(RequestResponse& aResponse) {
1829 AssertIsOnOwningThread();
1831 StorageNameResponse storageNameResponse;
1833 storageNameResponse.name() = mName;
1835 aResponse = storageNameResponse;
1838 void StorageNameOp::CloseDirectory() { AssertIsOnOwningThread(); }
1840 InitializedRequestBase::InitializedRequestBase(
1841 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName)
1842 : ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
1843 mInitialized(false) {
1844 AssertIsOnOwningThread();
1847 RefPtr<BoolPromise> InitializedRequestBase::OpenDirectory() {
1848 AssertIsOnOwningThread();
1850 return BoolPromise::CreateAndResolve(true, __func__);
1853 void InitializedRequestBase::CloseDirectory() { AssertIsOnOwningThread(); }
1855 nsresult StorageInitializedOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1856 AssertIsOnIOThread();
1858 AUTO_PROFILER_LABEL("StorageInitializedOp::DoDirectoryWork", OTHER);
1860 mInitialized = aQuotaManager.IsStorageInitializedInternal();
1862 return NS_OK;
1865 bool StorageInitializedOp::UnwrapResolveValue() {
1866 AssertIsOnOwningThread();
1868 return mInitialized;
1871 nsresult PersistentStorageInitializedOp::DoDirectoryWork(
1872 QuotaManager& aQuotaManager) {
1873 AssertIsOnIOThread();
1875 AUTO_PROFILER_LABEL("PersistentStorageInitializedOp::DoDirectoryWork", OTHER);
1877 mInitialized = aQuotaManager.IsPersistentStorageInitializedInternal();
1879 return NS_OK;
1882 bool PersistentStorageInitializedOp::UnwrapResolveValue() {
1883 AssertIsOnOwningThread();
1885 return mInitialized;
1888 nsresult TemporaryStorageInitializedOp::DoDirectoryWork(
1889 QuotaManager& aQuotaManager) {
1890 AssertIsOnIOThread();
1892 AUTO_PROFILER_LABEL("TemporaryStorageInitializedOp::DoDirectoryWork", OTHER);
1894 mInitialized = aQuotaManager.IsTemporaryStorageInitializedInternal();
1896 return NS_OK;
1899 bool TemporaryStorageInitializedOp::UnwrapResolveValue() {
1900 AssertIsOnOwningThread();
1902 return mInitialized;
1905 TemporaryGroupInitializedOp::TemporaryGroupInitializedOp(
1906 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1907 const PrincipalMetadata& aPrincipalMetadata)
1908 : ResolvableNormalOriginOp(std::move(aQuotaManager),
1909 "dom::quota::TemporaryGroupInitializedOp"),
1910 mPrincipalMetadata(aPrincipalMetadata),
1911 mInitialized(false) {
1912 AssertIsOnOwningThread();
1915 RefPtr<BoolPromise> TemporaryGroupInitializedOp::OpenDirectory() {
1916 AssertIsOnOwningThread();
1918 return BoolPromise::CreateAndResolve(true, __func__);
1921 nsresult TemporaryGroupInitializedOp::DoDirectoryWork(
1922 QuotaManager& aQuotaManager) {
1923 AssertIsOnIOThread();
1925 AUTO_PROFILER_LABEL("TemporaryGroupInitializedOp::DoDirectoryWork", OTHER);
1927 mInitialized =
1928 aQuotaManager.IsTemporaryGroupInitializedInternal(mPrincipalMetadata);
1930 return NS_OK;
1933 bool TemporaryGroupInitializedOp::UnwrapResolveValue() {
1934 AssertIsOnOwningThread();
1936 return mInitialized;
1939 void TemporaryGroupInitializedOp::CloseDirectory() { AssertIsOnOwningThread(); }
1941 InitializedOriginRequestBase::InitializedOriginRequestBase(
1942 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
1943 const PrincipalMetadata& aPrincipalMetadata)
1944 : ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
1945 mPrincipalMetadata(aPrincipalMetadata),
1946 mInitialized(false) {
1947 AssertIsOnOwningThread();
1950 RefPtr<BoolPromise> InitializedOriginRequestBase::OpenDirectory() {
1951 AssertIsOnOwningThread();
1953 return BoolPromise::CreateAndResolve(true, __func__);
1956 void InitializedOriginRequestBase::CloseDirectory() {
1957 AssertIsOnOwningThread();
1960 PersistentOriginInitializedOp::PersistentOriginInitializedOp(
1961 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1962 const OriginMetadata& aOriginMetadata)
1963 : InitializedOriginRequestBase(std::move(aQuotaManager),
1964 "dom::quota::PersistentOriginInitializedOp",
1965 aOriginMetadata) {
1966 AssertIsOnOwningThread();
1967 MOZ_ASSERT(aOriginMetadata.mPersistenceType == PERSISTENCE_TYPE_PERSISTENT);
1970 nsresult PersistentOriginInitializedOp::DoDirectoryWork(
1971 QuotaManager& aQuotaManager) {
1972 AssertIsOnIOThread();
1974 AUTO_PROFILER_LABEL("PersistentOriginInitializedOp::DoDirectoryWork", OTHER);
1976 mInitialized = aQuotaManager.IsPersistentOriginInitializedInternal(
1977 OriginMetadata{mPrincipalMetadata, PERSISTENCE_TYPE_PERSISTENT});
1979 return NS_OK;
1982 bool PersistentOriginInitializedOp::UnwrapResolveValue() {
1983 AssertIsOnOwningThread();
1985 return mInitialized;
1988 TemporaryOriginInitializedOp::TemporaryOriginInitializedOp(
1989 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1990 const OriginMetadata& aOriginMetadata)
1991 : InitializedOriginRequestBase(std::move(aQuotaManager),
1992 "dom::quota::TemporaryOriginInitializedOp",
1993 aOriginMetadata),
1994 mPersistenceType(aOriginMetadata.mPersistenceType) {
1995 AssertIsOnOwningThread();
1996 MOZ_ASSERT(aOriginMetadata.mPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
1999 nsresult TemporaryOriginInitializedOp::DoDirectoryWork(
2000 QuotaManager& aQuotaManager) {
2001 AssertIsOnIOThread();
2003 AUTO_PROFILER_LABEL("TemporaryOriginInitializedOp::DoDirectoryWork", OTHER);
2005 mInitialized = aQuotaManager.IsTemporaryOriginInitializedInternal(
2006 OriginMetadata{mPrincipalMetadata, mPersistenceType});
2008 return NS_OK;
2011 bool TemporaryOriginInitializedOp::UnwrapResolveValue() {
2012 AssertIsOnOwningThread();
2014 return mInitialized;
2017 InitOp::InitOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2018 RefPtr<UniversalDirectoryLock> aDirectoryLock)
2019 : ResolvableNormalOriginOp(std::move(aQuotaManager), "dom::quota::InitOp"),
2020 mDirectoryLock(std::move(aDirectoryLock)) {
2021 AssertIsOnOwningThread();
2022 MOZ_ASSERT(mDirectoryLock);
2025 RefPtr<BoolPromise> InitOp::OpenDirectory() {
2026 AssertIsOnOwningThread();
2027 MOZ_ASSERT(mDirectoryLock);
2029 return BoolPromise::CreateAndResolve(true, __func__);
2032 nsresult InitOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
2033 AssertIsOnIOThread();
2035 AUTO_PROFILER_LABEL("InitOp::DoDirectoryWork", OTHER);
2037 QM_TRY(MOZ_TO_RESULT(aQuotaManager.EnsureStorageIsInitializedInternal()));
2039 return NS_OK;
2042 bool InitOp::UnwrapResolveValue() { return true; }
2044 void InitOp::CloseDirectory() {
2045 AssertIsOnOwningThread();
2047 DropDirectoryLock(mDirectoryLock);
2050 InitializePersistentStorageOp::InitializePersistentStorageOp(
2051 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2052 RefPtr<UniversalDirectoryLock> aDirectoryLock)
2053 : ResolvableNormalOriginOp(std::move(aQuotaManager),
2054 "dom::quota::InitializePersistentStorageOp"),
2055 mDirectoryLock(std::move(aDirectoryLock)) {
2056 AssertIsOnOwningThread();
2059 RefPtr<BoolPromise> InitializePersistentStorageOp::OpenDirectory() {
2060 AssertIsOnOwningThread();
2061 MOZ_ASSERT(mDirectoryLock);
2063 return BoolPromise::CreateAndResolve(true, __func__);
2066 nsresult InitializePersistentStorageOp::DoDirectoryWork(
2067 QuotaManager& aQuotaManager) {
2068 AssertIsOnIOThread();
2070 AUTO_PROFILER_LABEL("InitializePersistentStorageOp::DoDirectoryWork", OTHER);
2072 QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
2073 NS_ERROR_NOT_INITIALIZED);
2075 QM_TRY(MOZ_TO_RESULT(
2076 aQuotaManager.EnsurePersistentStorageIsInitializedInternal()));
2078 return NS_OK;
2081 bool InitializePersistentStorageOp::UnwrapResolveValue() {
2082 AssertIsOnOwningThread();
2084 return true;
2087 void InitializePersistentStorageOp::CloseDirectory() {
2088 AssertIsOnOwningThread();
2090 DropDirectoryLock(mDirectoryLock);
2093 InitTemporaryStorageOp::InitTemporaryStorageOp(
2094 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2095 RefPtr<UniversalDirectoryLock> aDirectoryLock)
2096 : ResolvableNormalOriginOp(std::move(aQuotaManager),
2097 "dom::quota::InitTemporaryStorageOp"),
2098 mDirectoryLock(std::move(aDirectoryLock)) {
2099 AssertIsOnOwningThread();
2102 RefPtr<BoolPromise> InitTemporaryStorageOp::OpenDirectory() {
2103 AssertIsOnOwningThread();
2104 MOZ_ASSERT(mDirectoryLock);
2106 return BoolPromise::CreateAndResolve(true, __func__);
2109 nsresult InitTemporaryStorageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
2110 AssertIsOnIOThread();
2112 AUTO_PROFILER_LABEL("InitTemporaryStorageOp::DoDirectoryWork", OTHER);
2114 QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
2115 NS_ERROR_NOT_INITIALIZED);
2117 const bool wasInitialized =
2118 aQuotaManager.IsTemporaryStorageInitializedInternal();
2120 if (!wasInitialized) {
2121 QM_TRY(MOZ_TO_RESULT(
2122 aQuotaManager.EnsureTemporaryStorageIsInitializedInternal()));
2124 mAllTemporaryGroups = Some(aQuotaManager.GetAllTemporaryGroups());
2127 return NS_OK;
2130 MaybePrincipalMetadataArray InitTemporaryStorageOp::UnwrapResolveValue() {
2131 AssertIsOnOwningThread();
2133 return std::move(mAllTemporaryGroups);
2136 void InitTemporaryStorageOp::CloseDirectory() {
2137 AssertIsOnOwningThread();
2139 DropDirectoryLock(mDirectoryLock);
2142 InitializeTemporaryGroupOp::InitializeTemporaryGroupOp(
2143 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2144 const PrincipalMetadata& aPrincipalMetadata,
2145 RefPtr<UniversalDirectoryLock> aDirectoryLock)
2146 : ResolvableNormalOriginOp(std::move(aQuotaManager),
2147 "dom::quota::InitializeTemporaryGroupOp"),
2148 mPrincipalMetadata(aPrincipalMetadata),
2149 mDirectoryLock(std::move(aDirectoryLock)) {
2150 AssertIsOnOwningThread();
2153 RefPtr<BoolPromise> InitializeTemporaryGroupOp::OpenDirectory() {
2154 AssertIsOnOwningThread();
2155 MOZ_ASSERT(mDirectoryLock);
2157 return BoolPromise::CreateAndResolve(true, __func__);
2160 nsresult InitializeTemporaryGroupOp::DoDirectoryWork(
2161 QuotaManager& aQuotaManager) {
2162 AssertIsOnIOThread();
2164 AUTO_PROFILER_LABEL("InitializeTemporaryGroupOp::DoDirectoryWork", OTHER);
2166 QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
2167 NS_ERROR_NOT_INITIALIZED);
2169 QM_TRY(OkIf(aQuotaManager.IsTemporaryStorageInitializedInternal()),
2170 NS_ERROR_NOT_INITIALIZED);
2172 QM_TRY(aQuotaManager.EnsureTemporaryGroupIsInitializedInternal(
2173 mPrincipalMetadata));
2175 return NS_OK;
2178 bool InitializeTemporaryGroupOp::UnwrapResolveValue() {
2179 AssertIsOnOwningThread();
2181 return true;
2184 void InitializeTemporaryGroupOp::CloseDirectory() {
2185 AssertIsOnOwningThread();
2187 DropDirectoryLock(mDirectoryLock);
2190 InitializeOriginRequestBase::InitializeOriginRequestBase(
2191 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
2192 const PrincipalMetadata& aPrincipalMetadata,
2193 RefPtr<UniversalDirectoryLock> aDirectoryLock)
2194 : ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
2195 mPrincipalMetadata(aPrincipalMetadata),
2196 mDirectoryLock(std::move(aDirectoryLock)),
2197 mCreated(false) {
2198 AssertIsOnOwningThread();
2201 RefPtr<BoolPromise> InitializeOriginRequestBase::OpenDirectory() {
2202 AssertIsOnOwningThread();
2203 MOZ_ASSERT(mDirectoryLock);
2205 return BoolPromise::CreateAndResolve(true, __func__);
2208 void InitializeOriginRequestBase::CloseDirectory() {
2209 AssertIsOnOwningThread();
2211 DropDirectoryLockIfNotDropped(mDirectoryLock);
2214 InitializePersistentOriginOp::InitializePersistentOriginOp(
2215 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2216 const OriginMetadata& aOriginMetadata,
2217 RefPtr<UniversalDirectoryLock> aDirectoryLock)
2218 : InitializeOriginRequestBase(std::move(aQuotaManager),
2219 "dom::quota::InitializePersistentOriginOp",
2220 aOriginMetadata, std::move(aDirectoryLock)) {
2221 AssertIsOnOwningThread();
2222 MOZ_ASSERT(aOriginMetadata.mPersistenceType == PERSISTENCE_TYPE_PERSISTENT);
2225 nsresult InitializePersistentOriginOp::DoDirectoryWork(
2226 QuotaManager& aQuotaManager) {
2227 AssertIsOnIOThread();
2229 AUTO_PROFILER_LABEL("InitializePersistentOriginOp::DoDirectoryWork", OTHER);
2231 QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
2232 NS_ERROR_NOT_INITIALIZED);
2234 QM_TRY_UNWRAP(
2235 mCreated,
2236 (aQuotaManager
2237 .EnsurePersistentOriginIsInitializedInternal(
2238 OriginMetadata{mPrincipalMetadata, PERSISTENCE_TYPE_PERSISTENT})
2239 .map([](const auto& res) { return res.second; })));
2241 return NS_OK;
2244 bool InitializePersistentOriginOp::UnwrapResolveValue() {
2245 AssertIsOnOwningThread();
2247 return mCreated;
2250 InitializeTemporaryOriginOp::InitializeTemporaryOriginOp(
2251 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2252 const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent,
2253 RefPtr<UniversalDirectoryLock> aDirectoryLock)
2254 : InitializeOriginRequestBase(std::move(aQuotaManager),
2255 "dom::quota::InitializeTemporaryOriginOp",
2256 aOriginMetadata, std::move(aDirectoryLock)),
2257 mPersistenceType(aOriginMetadata.mPersistenceType),
2258 mCreateIfNonExistent(aCreateIfNonExistent) {
2259 AssertIsOnOwningThread();
2260 MOZ_ASSERT(aOriginMetadata.mPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
2263 nsresult InitializeTemporaryOriginOp::DoDirectoryWork(
2264 QuotaManager& aQuotaManager) {
2265 AssertIsOnIOThread();
2267 AUTO_PROFILER_LABEL("InitializeTemporaryOriginOp::DoDirectoryWork", OTHER);
2269 QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
2270 NS_ERROR_NOT_INITIALIZED);
2272 QM_TRY(OkIf(aQuotaManager.IsTemporaryStorageInitializedInternal()),
2273 NS_ERROR_NOT_INITIALIZED);
2275 QM_TRY_UNWRAP(mCreated,
2276 (aQuotaManager
2277 .EnsureTemporaryOriginIsInitializedInternal(
2278 OriginMetadata{mPrincipalMetadata, mPersistenceType},
2279 mCreateIfNonExistent)
2280 .map([](const auto& res) { return res.second; })));
2282 return NS_OK;
2285 bool InitializeTemporaryOriginOp::UnwrapResolveValue() {
2286 AssertIsOnOwningThread();
2288 return mCreated;
2291 InitializeClientBase::InitializeClientBase(
2292 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
2293 const PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
2294 Client::Type aClientType)
2295 : ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
2296 mPrincipalInfo(aPrincipalInfo),
2297 mPersistenceType(aPersistenceType),
2298 mClientType(aClientType),
2299 mCreated(false) {
2300 AssertIsOnOwningThread();
2303 nsresult InitializeClientBase::DoInit(QuotaManager& aQuotaManager) {
2304 AssertIsOnOwningThread();
2306 QM_TRY_UNWRAP(
2307 PrincipalMetadata principalMetadata,
2308 GetInfoFromValidatedPrincipalInfo(aQuotaManager, mPrincipalInfo));
2310 principalMetadata.AssertInvariants();
2312 mClientMetadata = {
2313 OriginMetadata{std::move(principalMetadata), mPersistenceType},
2314 mClientType};
2316 return NS_OK;
2319 RefPtr<BoolPromise> InitializeClientBase::OpenDirectory() {
2320 AssertIsOnOwningThread();
2322 mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
2323 PersistenceScope::CreateFromValue(mPersistenceType),
2324 OriginScope::FromOrigin(mClientMetadata),
2325 Nullable(mClientMetadata.mClientType), /* aExclusive */ false);
2327 return mDirectoryLock->Acquire();
2330 void InitializeClientBase::CloseDirectory() {
2331 AssertIsOnOwningThread();
2333 DropDirectoryLockIfNotDropped(mDirectoryLock);
2336 InitializePersistentClientOp::InitializePersistentClientOp(
2337 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2338 const PrincipalInfo& aPrincipalInfo, Client::Type aClientType)
2339 : InitializeClientBase(
2340 std::move(aQuotaManager), "dom::quota::InitializePersistentClientOp",
2341 PERSISTENCE_TYPE_PERSISTENT, aPrincipalInfo, aClientType) {
2342 AssertIsOnOwningThread();
2345 nsresult InitializePersistentClientOp::DoDirectoryWork(
2346 QuotaManager& aQuotaManager) {
2347 AssertIsOnIOThread();
2349 AUTO_PROFILER_LABEL("InitializePersistentClientOp::DoDirectoryWork", OTHER);
2351 QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsStorageInitializedInternal()),
2352 NS_ERROR_FAILURE);
2354 QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsPersistentOriginInitializedInternal(
2355 mClientMetadata.mOrigin)),
2356 NS_ERROR_FAILURE);
2358 QM_TRY_UNWRAP(
2359 mCreated,
2360 (aQuotaManager.EnsurePersistentClientIsInitialized(mClientMetadata)
2361 .map([](const auto& res) { return res.second; })));
2363 return NS_OK;
2366 bool InitializePersistentClientOp::UnwrapResolveValue() {
2367 AssertIsOnOwningThread();
2369 return mCreated;
2372 InitializeTemporaryClientOp::InitializeTemporaryClientOp(
2373 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2374 PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
2375 Client::Type aClientType)
2376 : InitializeClientBase(std::move(aQuotaManager),
2377 "dom::quota::InitializeTemporaryClientOp",
2378 aPersistenceType, aPrincipalInfo, aClientType) {
2379 AssertIsOnOwningThread();
2382 nsresult InitializeTemporaryClientOp::DoDirectoryWork(
2383 QuotaManager& aQuotaManager) {
2384 AssertIsOnIOThread();
2386 AUTO_PROFILER_LABEL("InitializeTemporaryClientOp::DoDirectoryWork", OTHER);
2388 QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsStorageInitializedInternal()),
2389 NS_ERROR_FAILURE);
2391 QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsTemporaryStorageInitializedInternal()),
2392 NS_ERROR_FAILURE);
2394 QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsTemporaryOriginInitializedInternal(
2395 mClientMetadata)),
2396 NS_ERROR_FAILURE);
2398 QM_TRY_UNWRAP(
2399 mCreated,
2400 (aQuotaManager.EnsureTemporaryClientIsInitialized(mClientMetadata)
2401 .map([](const auto& res) { return res.second; })));
2403 return NS_OK;
2406 bool InitializeTemporaryClientOp::UnwrapResolveValue() {
2407 AssertIsOnOwningThread();
2409 return mCreated;
2412 GetFullOriginMetadataOp::GetFullOriginMetadataOp(
2413 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2414 const GetFullOriginMetadataParams& aParams)
2415 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
2416 "dom::quota::GetFullOriginMetadataOp"),
2417 mParams(aParams) {
2418 AssertIsOnOwningThread();
2421 nsresult GetFullOriginMetadataOp::DoInit(QuotaManager& aQuotaManager) {
2422 AssertIsOnOwningThread();
2424 QM_TRY_UNWRAP(PrincipalMetadata principalMetadata,
2425 GetInfoFromValidatedPrincipalInfo(aQuotaManager,
2426 mParams.principalInfo()));
2428 principalMetadata.AssertInvariants();
2430 mOriginMetadata = {std::move(principalMetadata), mParams.persistenceType()};
2432 return NS_OK;
2435 RefPtr<BoolPromise> GetFullOriginMetadataOp::OpenDirectory() {
2436 AssertIsOnOwningThread();
2438 return OpenStorageDirectory(
2439 PersistenceScope::CreateFromValue(mOriginMetadata.mPersistenceType),
2440 OriginScope::FromOrigin(mOriginMetadata), Nullable<Client::Type>(),
2441 /* aExclusive */ false,
2442 /* aInitializeOrigins */ true);
2445 nsresult GetFullOriginMetadataOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
2446 AssertIsOnIOThread();
2447 aQuotaManager.AssertStorageIsInitializedInternal();
2449 AUTO_PROFILER_LABEL("GetFullOriginMetadataOp::DoDirectoryWork", OTHER);
2451 // Get metadata cached in memory (the method doesn't have to stat any
2452 // files).
2453 mMaybeFullOriginMetadata =
2454 aQuotaManager.GetFullOriginMetadata(mOriginMetadata);
2456 return NS_OK;
2459 void GetFullOriginMetadataOp::GetResponse(RequestResponse& aResponse) {
2460 AssertIsOnOwningThread();
2462 aResponse = GetFullOriginMetadataResponse();
2463 aResponse.get_GetFullOriginMetadataResponse().maybeFullOriginMetadata() =
2464 std::move(mMaybeFullOriginMetadata);
2467 void GetFullOriginMetadataOp::CloseDirectory() {
2468 AssertIsOnOwningThread();
2470 SafeDropDirectoryLock(mDirectoryLock);
2473 GetCachedOriginUsageOp::GetCachedOriginUsageOp(
2474 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2475 const PrincipalInfo& aPrincipalInfo)
2476 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
2477 "dom::quota::GetCachedOriginUsageOp"),
2478 mPrincipalInfo(aPrincipalInfo),
2479 mUsage(0) {
2480 AssertIsOnOwningThread();
2483 nsresult GetCachedOriginUsageOp::DoInit(QuotaManager& aQuotaManager) {
2484 AssertIsOnOwningThread();
2486 QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
2487 aQuotaManager, mPrincipalInfo));
2489 mPrincipalMetadata.AssertInvariants();
2491 return NS_OK;
2494 RefPtr<BoolPromise> GetCachedOriginUsageOp::OpenDirectory() {
2495 AssertIsOnOwningThread();
2497 return OpenStorageDirectory(
2498 PersistenceScope::CreateFromSet(PERSISTENCE_TYPE_TEMPORARY,
2499 PERSISTENCE_TYPE_DEFAULT,
2500 PERSISTENCE_TYPE_PRIVATE),
2501 OriginScope::FromOrigin(mPrincipalMetadata), Nullable<Client::Type>(),
2502 /* aExclusive */ false);
2505 nsresult GetCachedOriginUsageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
2506 AssertIsOnIOThread();
2507 MOZ_ASSERT(mUsage == 0);
2509 AUTO_PROFILER_LABEL("GetCachedOriginUsageOp::DoDirectoryWork", OTHER);
2511 // If temporary storage hasn't been initialized yet, there's no cached usage
2512 // to report.
2513 if (!aQuotaManager.IsTemporaryStorageInitializedInternal()) {
2514 return NS_OK;
2517 // Get cached usage (the method doesn't have to stat any files).
2518 mUsage = aQuotaManager.GetOriginUsage(mPrincipalMetadata);
2520 return NS_OK;
2523 uint64_t GetCachedOriginUsageOp::UnwrapResolveValue() {
2524 AssertIsOnOwningThread();
2526 return mUsage;
2529 void GetCachedOriginUsageOp::CloseDirectory() {
2530 AssertIsOnOwningThread();
2532 SafeDropDirectoryLock(mDirectoryLock);
2535 ListCachedOriginsOp::ListCachedOriginsOp(
2536 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
2537 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
2538 "dom::quota::ListCachedOriginsOp") {
2539 AssertIsOnOwningThread();
2542 RefPtr<BoolPromise> ListCachedOriginsOp::OpenDirectory() {
2543 AssertIsOnOwningThread();
2545 return OpenStorageDirectory(PersistenceScope::CreateFromNull(),
2546 OriginScope::FromNull(), Nullable<Client::Type>(),
2547 /* aExclusive */ false);
2550 nsresult ListCachedOriginsOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
2551 AssertIsOnIOThread();
2552 MOZ_ASSERT(mOrigins.Length() == 0);
2554 AUTO_PROFILER_LABEL("ListCachedOriginsOp::DoDirectoryWork", OTHER);
2556 // If temporary storage hasn't been initialized yet, there are no cached
2557 // origins to report.
2558 if (!aQuotaManager.IsTemporaryStorageInitializedInternal()) {
2559 return NS_OK;
2562 // Get cached origins (the method doesn't have to stat any files).
2563 OriginMetadataArray originMetadataArray =
2564 aQuotaManager.GetAllTemporaryOrigins();
2566 std::transform(originMetadataArray.cbegin(), originMetadataArray.cend(),
2567 MakeBackInserter(mOrigins), [](const auto& originMetadata) {
2568 return originMetadata.mOrigin;
2571 return NS_OK;
2574 CStringArray ListCachedOriginsOp::UnwrapResolveValue() {
2575 AssertIsOnOwningThread();
2576 MOZ_ASSERT(!ResolveValueConsumed());
2578 return std::move(mOrigins);
2581 void ListCachedOriginsOp::CloseDirectory() {
2582 AssertIsOnOwningThread();
2584 SafeDropDirectoryLock(mDirectoryLock);
2587 ClearStorageOp::ClearStorageOp(
2588 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
2589 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
2590 "dom::quota::ClearStorageOp") {
2591 AssertIsOnOwningThread();
2594 void ClearStorageOp::DeleteFiles(QuotaManager& aQuotaManager) {
2595 AssertIsOnIOThread();
2597 nsresult rv = aQuotaManager.AboutToClearOrigins(
2598 PersistenceScope::CreateFromNull(), OriginScope::FromNull(),
2599 Nullable<Client::Type>());
2600 if (NS_WARN_IF(NS_FAILED(rv))) {
2601 return;
2604 auto directoryOrErr = QM_NewLocalFile(aQuotaManager.GetStoragePath());
2605 if (NS_WARN_IF(directoryOrErr.isErr())) {
2606 return;
2609 nsCOMPtr<nsIFile> directory = directoryOrErr.unwrap();
2611 rv = directory->Remove(true);
2612 if (rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
2613 // This should never fail if we've closed all storage connections
2614 // correctly...
2615 MOZ_ASSERT(false, "Failed to remove storage directory!");
2619 void ClearStorageOp::DeleteStorageFile(QuotaManager& aQuotaManager) {
2620 AssertIsOnIOThread();
2622 QM_TRY_INSPECT(const auto& storageFile,
2623 QM_NewLocalFile(aQuotaManager.GetBasePath()), QM_VOID);
2625 QM_TRY(MOZ_TO_RESULT(storageFile->Append(aQuotaManager.GetStorageName() +
2626 kSQLiteSuffix)),
2627 QM_VOID);
2629 const nsresult rv = storageFile->Remove(true);
2630 if (rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
2631 // This should never fail if we've closed the storage connection
2632 // correctly...
2633 MOZ_ASSERT(false, "Failed to remove storage file!");
2637 RefPtr<BoolPromise> ClearStorageOp::OpenDirectory() {
2638 AssertIsOnOwningThread();
2640 // Clear directory lock tables (which also saves origin access time) before
2641 // acquiring the exclusive lock below. Otherwise, saving of origin access
2642 // time would be scheduled after storage clearing and that would initialize
2643 // storage again in the end.
2644 mQuotaManager->ClearDirectoryLockTables();
2646 return OpenStorageDirectory(PersistenceScope::CreateFromNull(),
2647 OriginScope::FromNull(), Nullable<Client::Type>(),
2648 /* aExclusive */ true,
2649 /* aInitializeOrigins */ false,
2650 DirectoryLockCategory::UninitStorage);
2653 nsresult ClearStorageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
2654 AssertIsOnIOThread();
2655 aQuotaManager.AssertStorageIsInitializedInternal();
2657 AUTO_PROFILER_LABEL("ClearStorageOp::DoDirectoryWork", OTHER);
2659 DeleteFiles(aQuotaManager);
2661 aQuotaManager.RemoveQuota();
2663 aQuotaManager.ShutdownStorageInternal();
2665 DeleteStorageFile(aQuotaManager);
2667 return NS_OK;
2670 bool ClearStorageOp::UnwrapResolveValue() {
2671 AssertIsOnOwningThread();
2673 return true;
2676 void ClearStorageOp::CloseDirectory() {
2677 AssertIsOnOwningThread();
2679 SafeDropDirectoryLock(mDirectoryLock);
2682 void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
2683 const OriginMetadata& aOriginMetadata) {
2684 AssertIsOnIOThread();
2686 DeleteFilesInternal(
2687 aQuotaManager, aOriginMetadata.mPersistenceType,
2688 OriginScope::FromOrigin(aOriginMetadata),
2689 [&aQuotaManager, &aOriginMetadata](
2690 const std::function<Result<Ok, nsresult>(nsCOMPtr<nsIFile>)>& aBody)
2691 -> Result<Ok, nsresult> {
2692 QM_TRY_UNWRAP(auto directory,
2693 aQuotaManager.GetOriginDirectory(aOriginMetadata));
2695 // We're not checking if the origin directory actualy exists because
2696 // it can be a pending origin (OriginInfo does exist but the origin
2697 // directory hasn't been created yet).
2699 QM_TRY_RETURN(aBody(std::move(directory)));
2703 void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
2704 PersistenceType aPersistenceType,
2705 const OriginScope& aOriginScope) {
2706 AssertIsOnIOThread();
2708 DeleteFilesInternal(
2709 aQuotaManager, aPersistenceType, aOriginScope,
2710 [&aQuotaManager, &aPersistenceType](
2711 const std::function<Result<Ok, nsresult>(nsCOMPtr<nsIFile>)>& aBody)
2712 -> Result<Ok, nsresult> {
2713 QM_TRY_INSPECT(
2714 const auto& directory,
2715 QM_NewLocalFile(aQuotaManager.GetStoragePath(aPersistenceType)));
2717 QM_TRY_INSPECT(const bool& exists,
2718 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
2720 if (!exists) {
2721 return Ok{};
2724 QM_TRY(CollectEachFile(*directory, aBody));
2726 // CollectEachFile above only consulted the file-system to get a list of
2727 // known origins, but we also need to include origins that have pending
2728 // quota usage.
2730 nsTArray<OriginMetadata> originMetadataArray;
2731 aQuotaManager.CollectPendingOriginsForListing(
2732 [aPersistenceType, &originMetadataArray](const auto& originInfo) {
2733 if (originInfo->GetGroupInfo()->GetPersistenceType() !=
2734 aPersistenceType) {
2735 return;
2737 originMetadataArray.AppendElement(
2738 originInfo->FlattenToOriginMetadata());
2741 if (originMetadataArray.IsEmpty()) {
2742 return Ok{};
2745 nsTArray<nsCOMPtr<nsIFile>> originDirectories;
2746 QM_TRY(TransformAbortOnErr(
2747 originMetadataArray, MakeBackInserter(originDirectories),
2748 [&aQuotaManager](const auto& originMetadata)
2749 -> Result<nsCOMPtr<nsIFile>, nsresult> {
2750 QM_TRY_UNWRAP(auto originDirectory,
2751 aQuotaManager.GetOriginDirectory(originMetadata));
2752 return originDirectory;
2753 }));
2755 QM_TRY_RETURN(CollectEachInRange(originDirectories, aBody));
2759 template <typename FileCollector>
2760 void ClearRequestBase::DeleteFilesInternal(
2761 QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
2762 const OriginScope& aOriginScope, const FileCollector& aFileCollector) {
2763 AssertIsOnIOThread();
2765 QM_TRY(MOZ_TO_RESULT(aQuotaManager.AboutToClearOrigins(
2766 PersistenceScope::CreateFromValue(aPersistenceType), aOriginScope,
2767 Nullable<Client::Type>())),
2768 QM_VOID);
2770 nsTArray<nsCOMPtr<nsIFile>> directoriesForRemovalRetry;
2772 aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
2773 "ClearRequestBase: Starting deleting files"_ns);
2775 QM_TRY(
2776 aFileCollector([&originScope = aOriginScope, aPersistenceType,
2777 &aQuotaManager, &directoriesForRemovalRetry,
2778 this](nsCOMPtr<nsIFile> file)
2779 -> mozilla::Result<Ok, nsresult> {
2780 QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*file));
2782 QM_TRY_INSPECT(
2783 const auto& leafName,
2784 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, file, GetLeafName));
2786 switch (dirEntryKind) {
2787 case nsIFileKind::ExistsAsDirectory: {
2788 QM_TRY_UNWRAP(auto maybeMetadata,
2789 QM_OR_ELSE_WARN_IF(
2790 // Expression
2791 aQuotaManager.GetOriginMetadata(file).map(
2792 [](auto metadata) -> Maybe<OriginMetadata> {
2793 return Some(std::move(metadata));
2795 // Predicate.
2796 IsSpecificError<NS_ERROR_MALFORMED_URI>,
2797 // Fallback.
2798 ErrToDefaultOk<Maybe<OriginMetadata>>));
2800 if (!maybeMetadata) {
2801 // Unknown directories during clearing are allowed. Just
2802 // warn if we find them.
2803 UNKNOWN_FILE_WARNING(leafName);
2804 break;
2807 auto metadata = maybeMetadata.extract();
2809 MOZ_ASSERT(metadata.mPersistenceType == aPersistenceType);
2811 // Skip the origin directory if it doesn't match the pattern.
2812 if (!originScope.Matches(OriginScope::FromOrigin(metadata))) {
2813 break;
2816 // We can't guarantee that this will always succeed on
2817 // Windows...
2818 QM_WARNONLY_TRY(
2819 aQuotaManager.RemoveOriginDirectory(*file), [&](const auto&) {
2820 directoriesForRemovalRetry.AppendElement(std::move(file));
2823 mOriginMetadataArray.AppendElement(metadata);
2825 const bool initialized =
2826 aPersistenceType == PERSISTENCE_TYPE_PERSISTENT
2827 ? aQuotaManager.IsPersistentOriginInitializedInternal(
2828 metadata.mOrigin)
2829 : aQuotaManager.IsTemporaryStorageInitializedInternal();
2831 // If it hasn't been initialized, we don't need to update the
2832 // quota and notify the removing client, but we do need to remove
2833 // it from quota info cache.
2834 if (!initialized) {
2835 aQuotaManager.RemoveOriginFromCache(metadata);
2836 break;
2839 if (aPersistenceType != PERSISTENCE_TYPE_PERSISTENT) {
2840 aQuotaManager.RemoveQuotaForOrigin(aPersistenceType, metadata);
2843 aQuotaManager.OriginClearCompleted(metadata,
2844 Nullable<Client::Type>());
2846 break;
2849 case nsIFileKind::ExistsAsFile: {
2850 // Unknown files during clearing are allowed. Just warn if we
2851 // find them.
2852 if (!IsOSMetadata(leafName)) {
2853 UNKNOWN_FILE_WARNING(leafName);
2856 break;
2859 case nsIFileKind::DoesNotExist: {
2860 if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
2861 break;
2864 QM_TRY_UNWRAP(auto metadata, aQuotaManager.GetOriginMetadata(file));
2866 MOZ_ASSERT(metadata.mPersistenceType == aPersistenceType);
2868 // Skip the origin directory if it doesn't match the pattern.
2869 if (!originScope.Matches(OriginScope::FromOrigin(metadata))) {
2870 break;
2873 if (!aQuotaManager.IsPendingOrigin(metadata)) {
2874 break;
2877 mOriginMetadataArray.AppendElement(metadata);
2879 aQuotaManager.RemoveQuotaForOrigin(aPersistenceType, metadata);
2881 aQuotaManager.OriginClearCompleted(metadata,
2882 Nullable<Client::Type>());
2884 break;
2888 mIterations++;
2889 aQuotaManager.IncreaseTotalDirectoryIterations();
2891 return Ok{};
2893 QM_VOID);
2895 // Retry removing any directories that failed to be removed earlier now.
2897 // XXX This will still block this operation. We might instead dispatch a
2898 // runnable to our own thread for each retry round with a timer. We must
2899 // ensure that the directory lock is upheld until we complete or give up
2900 // though.
2901 for (uint32_t index = 0; index < 10; index++) {
2902 aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
2903 return nsPrintfCString(
2904 "ClearRequestBase: Starting repeated directory removal #%d", index);
2907 for (auto&& file : std::exchange(directoriesForRemovalRetry,
2908 nsTArray<nsCOMPtr<nsIFile>>{})) {
2909 QM_WARNONLY_TRY(
2910 aQuotaManager.RemoveOriginDirectory(*file),
2911 ([&directoriesForRemovalRetry, &file](const auto&) {
2912 directoriesForRemovalRetry.AppendElement(std::move(file));
2913 }));
2916 aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
2917 return nsPrintfCString(
2918 "ClearRequestBase: Completed repeated directory removal #%d", index);
2921 if (directoriesForRemovalRetry.IsEmpty()) {
2922 break;
2925 aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
2926 return nsPrintfCString("ClearRequestBase: Before sleep #%d", index);
2929 PR_Sleep(PR_MillisecondsToInterval(200));
2931 aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
2932 return nsPrintfCString("ClearRequestBase: After sleep #%d", index);
2936 QM_WARNONLY_TRY(OkIf(directoriesForRemovalRetry.IsEmpty()));
2938 aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
2939 "ClearRequestBase: Completed deleting files"_ns);
2942 ClearOriginOp::ClearOriginOp(
2943 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2944 const mozilla::Maybe<PersistenceType>& aPersistenceType,
2945 const PrincipalInfo& aPrincipalInfo)
2946 : ClearRequestBase(std::move(aQuotaManager), "dom::quota::ClearOriginOp"),
2947 mPrincipalInfo(aPrincipalInfo),
2948 mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
2949 *aPersistenceType)
2950 : PersistenceScope::CreateFromNull()) {
2951 AssertIsOnOwningThread();
2954 nsresult ClearOriginOp::DoInit(QuotaManager& aQuotaManager) {
2955 AssertIsOnOwningThread();
2957 QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
2958 aQuotaManager, mPrincipalInfo));
2960 mPrincipalMetadata.AssertInvariants();
2962 return NS_OK;
2965 RefPtr<BoolPromise> ClearOriginOp::OpenDirectory() {
2966 AssertIsOnOwningThread();
2968 return OpenStorageDirectory(
2969 mPersistenceScope, OriginScope::FromOrigin(mPrincipalMetadata),
2970 Nullable<Client::Type>(), /* aExclusive */ true,
2971 /* aInitializeOrigins */ false, DirectoryLockCategory::UninitOrigins);
2974 nsresult ClearOriginOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
2975 AssertIsOnIOThread();
2976 aQuotaManager.AssertStorageIsInitializedInternal();
2978 AUTO_PROFILER_LABEL("ClearRequestBase::DoDirectoryWork", OTHER);
2980 if (mPersistenceScope.IsNull()) {
2981 for (const PersistenceType type : kAllPersistenceTypes) {
2982 DeleteFiles(aQuotaManager, OriginMetadata(mPrincipalMetadata, type));
2984 } else {
2985 MOZ_ASSERT(mPersistenceScope.IsValue());
2987 DeleteFiles(aQuotaManager, OriginMetadata(mPrincipalMetadata,
2988 mPersistenceScope.GetValue()));
2991 return NS_OK;
2994 OriginMetadataArray ClearOriginOp::UnwrapResolveValue() {
2995 AssertIsOnOwningThread();
2997 return std::move(mOriginMetadataArray);
3000 void ClearOriginOp::CloseDirectory() {
3001 AssertIsOnOwningThread();
3003 SafeDropDirectoryLock(mDirectoryLock);
3006 ClearClientOp::ClearClientOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
3007 mozilla::Maybe<PersistenceType> aPersistenceType,
3008 const PrincipalInfo& aPrincipalInfo,
3009 Client::Type aClientType)
3010 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
3011 "dom::quota::ClearClientOp"),
3012 mPrincipalInfo(aPrincipalInfo),
3013 mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
3014 *aPersistenceType)
3015 : PersistenceScope::CreateFromNull()),
3016 mClientType(aClientType) {
3017 AssertIsOnOwningThread();
3020 nsresult ClearClientOp::DoInit(QuotaManager& aQuotaManager) {
3021 AssertIsOnOwningThread();
3023 QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
3024 aQuotaManager, mPrincipalInfo));
3026 mPrincipalMetadata.AssertInvariants();
3028 return NS_OK;
3031 RefPtr<BoolPromise> ClearClientOp::OpenDirectory() {
3032 AssertIsOnOwningThread();
3034 return OpenStorageDirectory(mPersistenceScope,
3035 OriginScope::FromOrigin(mPrincipalMetadata),
3036 Nullable(mClientType), /* aExclusive */ true);
3039 void ClearClientOp::DeleteFiles(const ClientMetadata& aClientMetadata) {
3040 AssertIsOnIOThread();
3042 QM_TRY(
3043 MOZ_TO_RESULT(mQuotaManager->AboutToClearOrigins(
3044 PersistenceScope::CreateFromValue(aClientMetadata.mPersistenceType),
3045 OriginScope::FromOrigin(aClientMetadata),
3046 Nullable(aClientMetadata.mClientType))),
3047 QM_VOID);
3049 QM_TRY_INSPECT(const auto& directory,
3050 mQuotaManager->GetOriginDirectory(aClientMetadata), QM_VOID);
3052 QM_TRY(MOZ_TO_RESULT(directory->Append(
3053 Client::TypeToString(aClientMetadata.mClientType))),
3054 QM_VOID);
3056 QM_TRY_INSPECT(const bool& exists,
3057 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists), QM_VOID);
3058 if (!exists) {
3059 return;
3062 QM_TRY(MOZ_TO_RESULT(directory->Remove(true)), QM_VOID);
3064 const bool initialized =
3065 aClientMetadata.mPersistenceType == PERSISTENCE_TYPE_PERSISTENT
3066 ? mQuotaManager->IsPersistentOriginInitializedInternal(
3067 aClientMetadata.mOrigin)
3068 : mQuotaManager->IsTemporaryStorageInitializedInternal();
3070 if (!initialized) {
3071 return;
3074 if (aClientMetadata.mPersistenceType != PERSISTENCE_TYPE_PERSISTENT) {
3075 mQuotaManager->ResetUsageForClient(aClientMetadata);
3078 mQuotaManager->OriginClearCompleted(aClientMetadata,
3079 Nullable(aClientMetadata.mClientType));
3082 nsresult ClearClientOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
3083 AssertIsOnIOThread();
3084 aQuotaManager.AssertStorageIsInitializedInternal();
3086 AUTO_PROFILER_LABEL("ClearClientOp::DoDirectoryWork", OTHER);
3088 if (mPersistenceScope.IsNull()) {
3089 for (const PersistenceType type : kAllPersistenceTypes) {
3090 DeleteFiles(ClientMetadata(OriginMetadata(mPrincipalMetadata, type),
3091 mClientType));
3093 } else {
3094 MOZ_ASSERT(mPersistenceScope.IsValue());
3096 DeleteFiles(ClientMetadata(
3097 OriginMetadata(mPrincipalMetadata, mPersistenceScope.GetValue()),
3098 mClientType));
3101 return NS_OK;
3104 bool ClearClientOp::UnwrapResolveValue() {
3105 AssertIsOnOwningThread();
3107 return true;
3110 void ClearClientOp::CloseDirectory() {
3111 AssertIsOnOwningThread();
3113 SafeDropDirectoryLock(mDirectoryLock);
3116 ClearStoragesForOriginPrefixOp::ClearStoragesForOriginPrefixOp(
3117 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
3118 const Maybe<PersistenceType>& aPersistenceType,
3119 const PrincipalInfo& aPrincipalInfo)
3120 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
3121 "dom::quota::ClearStoragesForOriginPrefixOp"),
3122 mPrincipalInfo(aPrincipalInfo),
3123 mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
3124 *aPersistenceType)
3125 : PersistenceScope::CreateFromNull()) {
3126 AssertIsOnOwningThread();
3129 nsresult ClearStoragesForOriginPrefixOp::DoInit(QuotaManager& aQuotaManager) {
3130 AssertIsOnOwningThread();
3132 QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
3133 aQuotaManager, mPrincipalInfo));
3135 mPrincipalMetadata.AssertInvariants();
3137 return NS_OK;
3140 RefPtr<BoolPromise> ClearStoragesForOriginPrefixOp::OpenDirectory() {
3141 AssertIsOnOwningThread();
3143 return OpenStorageDirectory(
3144 mPersistenceScope, OriginScope::FromPrefix(mPrincipalMetadata),
3145 Nullable<Client::Type>(), /* aExclusive */ true,
3146 /* aInitializeOrigins */ false, DirectoryLockCategory::UninitOrigins);
3149 nsresult ClearStoragesForOriginPrefixOp::DoDirectoryWork(
3150 QuotaManager& aQuotaManager) {
3151 AssertIsOnIOThread();
3153 AUTO_PROFILER_LABEL("ClearStoragesForOriginPrefixOp::DoDirectoryWork", OTHER);
3155 if (mPersistenceScope.IsNull()) {
3156 for (const PersistenceType type : kAllPersistenceTypes) {
3157 DeleteFiles(aQuotaManager, type,
3158 OriginScope::FromPrefix(mPrincipalMetadata));
3160 } else {
3161 MOZ_ASSERT(mPersistenceScope.IsValue());
3163 DeleteFiles(aQuotaManager, mPersistenceScope.GetValue(),
3164 OriginScope::FromPrefix(mPrincipalMetadata));
3167 return NS_OK;
3170 OriginMetadataArray ClearStoragesForOriginPrefixOp::UnwrapResolveValue() {
3171 AssertIsOnOwningThread();
3173 return std::move(mOriginMetadataArray);
3176 void ClearStoragesForOriginPrefixOp::CloseDirectory() {
3177 AssertIsOnOwningThread();
3179 SafeDropDirectoryLock(mDirectoryLock);
3182 ClearDataOp::ClearDataOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
3183 const OriginAttributesPattern& aPattern)
3184 : ClearRequestBase(std::move(aQuotaManager), "dom::quota::ClearDataOp"),
3185 mPattern(aPattern) {}
3187 RefPtr<BoolPromise> ClearDataOp::OpenDirectory() {
3188 AssertIsOnOwningThread();
3190 return OpenStorageDirectory(
3191 PersistenceScope::CreateFromNull(), OriginScope::FromPattern(mPattern),
3192 Nullable<Client::Type>(), /* aExclusive */ true,
3193 /* aInitializeOrigins */ false, DirectoryLockCategory::UninitOrigins);
3196 nsresult ClearDataOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
3197 AssertIsOnIOThread();
3199 AUTO_PROFILER_LABEL("ClearRequestBase::DoDirectoryWork", OTHER);
3201 // Optimize clearing of thumbnail private identity temporary origins by
3202 // skipping potentially expensive temporary repository traversals when there
3203 // are no thumbnail private identity temporary origins (this is especially
3204 // important during shutdown).
3206 // XXX Can we do the skipping also when temporary storage is not initialized
3207 // (no new thumbnail private identity temporary origins could be created yet)?
3208 if (aQuotaManager.IsThumbnailPrivateIdentityIdKnown() &&
3209 IsUserContextPattern(mPattern,
3210 aQuotaManager.GetThumbnailPrivateIdentityId()) &&
3211 aQuotaManager.IsTemporaryStorageInitializedInternal() &&
3212 aQuotaManager.ThumbnailPrivateIdentityTemporaryOriginCount() == 0) {
3213 DeleteFiles(aQuotaManager, PERSISTENCE_TYPE_PERSISTENT,
3214 OriginScope::FromPattern(mPattern));
3216 return NS_OK;
3219 for (const PersistenceType type : kAllPersistenceTypes) {
3220 DeleteFiles(aQuotaManager, type, OriginScope::FromPattern(mPattern));
3223 return NS_OK;
3226 OriginMetadataArray ClearDataOp::UnwrapResolveValue() {
3227 AssertIsOnOwningThread();
3229 return std::move(mOriginMetadataArray);
3232 void ClearDataOp::CloseDirectory() {
3233 AssertIsOnOwningThread();
3235 SafeDropDirectoryLock(mDirectoryLock);
3238 ShutdownOriginOp::ShutdownOriginOp(
3239 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
3240 mozilla::Maybe<PersistenceType> aPersistenceType,
3241 const PrincipalInfo& aPrincipalInfo)
3242 : ResolvableNormalOriginOp(std::move(aQuotaManager),
3243 "dom::quota::ShutdownOriginOp"),
3244 mPrincipalInfo(aPrincipalInfo),
3245 mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
3246 *aPersistenceType)
3247 : PersistenceScope::CreateFromNull()) {
3248 AssertIsOnOwningThread();
3251 nsresult ShutdownOriginOp::DoInit(QuotaManager& aQuotaManager) {
3252 AssertIsOnOwningThread();
3254 QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
3255 aQuotaManager, mPrincipalInfo));
3257 mPrincipalMetadata.AssertInvariants();
3259 return NS_OK;
3262 RefPtr<BoolPromise> ShutdownOriginOp::OpenDirectory() {
3263 AssertIsOnOwningThread();
3265 mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
3266 mPersistenceScope, OriginScope::FromOrigin(mPrincipalMetadata),
3267 Nullable<Client::Type>(), /* aExclusive */ true,
3268 DirectoryLockCategory::UninitOrigins);
3270 return mDirectoryLock->Acquire();
3273 void ShutdownOriginOp::CollectOriginMetadata(
3274 const OriginMetadata& aOriginMetadata) {
3275 AssertIsOnIOThread();
3277 QM_TRY_INSPECT(const auto& directory,
3278 mQuotaManager->GetOriginDirectory(aOriginMetadata), QM_VOID);
3280 QM_TRY_INSPECT(const bool& exists,
3281 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists), QM_VOID);
3282 if (!exists) {
3283 if (aOriginMetadata.mPersistenceType != PERSISTENCE_TYPE_PERSISTENT &&
3284 mQuotaManager->IsPendingOrigin(aOriginMetadata)) {
3285 mOriginMetadataArray.AppendElement(aOriginMetadata);
3288 return;
3291 mOriginMetadataArray.AppendElement(aOriginMetadata);
3294 nsresult ShutdownOriginOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
3295 AssertIsOnIOThread();
3297 AUTO_PROFILER_LABEL("ShutdownOriginOp::DoDirectoryWork", OTHER);
3299 if (mPersistenceScope.IsNull()) {
3300 for (const PersistenceType type : kAllPersistenceTypes) {
3301 CollectOriginMetadata(OriginMetadata(mPrincipalMetadata, type));
3303 } else {
3304 MOZ_ASSERT(mPersistenceScope.IsValue());
3306 CollectOriginMetadata(
3307 OriginMetadata(mPrincipalMetadata, mPersistenceScope.GetValue()));
3310 return NS_OK;
3313 OriginMetadataArray ShutdownOriginOp::UnwrapResolveValue() {
3314 AssertIsOnOwningThread();
3316 return std::move(mOriginMetadataArray);
3319 void ShutdownOriginOp::CloseDirectory() {
3320 AssertIsOnOwningThread();
3322 DropDirectoryLockIfNotDropped(mDirectoryLock);
3325 ShutdownClientOp::ShutdownClientOp(
3326 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
3327 mozilla::Maybe<PersistenceType> aPersistenceType,
3328 const PrincipalInfo& aPrincipalInfo, Client::Type aClientType)
3329 : ResolvableNormalOriginOp(std::move(aQuotaManager),
3330 "dom::quota::ShutdownClientOp"),
3331 mPrincipalInfo(aPrincipalInfo),
3332 mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
3333 *aPersistenceType)
3334 : PersistenceScope::CreateFromNull()),
3335 mClientType(aClientType) {
3336 AssertIsOnOwningThread();
3339 nsresult ShutdownClientOp::DoInit(QuotaManager& aQuotaManager) {
3340 AssertIsOnOwningThread();
3342 QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
3343 aQuotaManager, mPrincipalInfo));
3345 mPrincipalMetadata.AssertInvariants();
3347 return NS_OK;
3350 RefPtr<BoolPromise> ShutdownClientOp::OpenDirectory() {
3351 AssertIsOnOwningThread();
3353 mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
3354 mPersistenceScope, OriginScope::FromOrigin(mPrincipalMetadata),
3355 Nullable(mClientType), /* aExclusive */ true);
3357 return mDirectoryLock->Acquire();
3360 nsresult ShutdownClientOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
3361 AssertIsOnIOThread();
3363 AUTO_PROFILER_LABEL("ShutdownClientOp::DoDirectoryWork", OTHER);
3365 // All the work is handled by NormalOriginOperationBase parent class. In
3366 // this particular case, we just needed to acquire an exclusive directory
3367 // lock and that's it.
3369 return NS_OK;
3372 bool ShutdownClientOp::UnwrapResolveValue() {
3373 AssertIsOnOwningThread();
3375 return true;
3378 void ShutdownClientOp::CloseDirectory() {
3379 AssertIsOnOwningThread();
3381 DropDirectoryLockIfNotDropped(mDirectoryLock);
3384 PersistRequestBase::PersistRequestBase(
3385 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
3386 const PrincipalInfo& aPrincipalInfo)
3387 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
3388 "dom::quota::PersistRequestBase"),
3389 mPrincipalInfo(aPrincipalInfo) {
3390 AssertIsOnOwningThread();
3393 nsresult PersistRequestBase::DoInit(QuotaManager& aQuotaManager) {
3394 AssertIsOnOwningThread();
3396 // Figure out which origin we're dealing with.
3397 QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
3398 aQuotaManager, mPrincipalInfo));
3400 mPrincipalMetadata.AssertInvariants();
3402 return NS_OK;
3405 RefPtr<BoolPromise> PersistRequestBase::OpenDirectory() {
3406 AssertIsOnOwningThread();
3408 return OpenStorageDirectory(
3409 PersistenceScope::CreateFromValue(PERSISTENCE_TYPE_DEFAULT),
3410 OriginScope::FromOrigin(mPrincipalMetadata), Nullable<Client::Type>(),
3411 /* aExclusive */ false);
3414 void PersistRequestBase::CloseDirectory() {
3415 AssertIsOnOwningThread();
3417 SafeDropDirectoryLock(mDirectoryLock);
3420 PersistedOp::PersistedOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
3421 const RequestParams& aParams)
3422 : PersistRequestBase(std::move(aQuotaManager),
3423 aParams.get_PersistedParams().principalInfo()),
3424 mPersisted(false) {
3425 MOZ_ASSERT(aParams.type() == RequestParams::TPersistedParams);
3428 nsresult PersistedOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
3429 AssertIsOnIOThread();
3430 aQuotaManager.AssertStorageIsInitializedInternal();
3432 AUTO_PROFILER_LABEL("PersistedOp::DoDirectoryWork", OTHER);
3434 const OriginMetadata originMetadata = {mPrincipalMetadata,
3435 PERSISTENCE_TYPE_DEFAULT};
3437 Nullable<bool> persisted = aQuotaManager.OriginPersisted(originMetadata);
3439 if (!persisted.IsNull()) {
3440 mPersisted = persisted.Value();
3441 return NS_OK;
3444 // If we get here, it means the origin hasn't been initialized yet.
3445 // Try to get the persisted flag from directory metadata on disk.
3447 QM_TRY_INSPECT(const auto& directory,
3448 aQuotaManager.GetOriginDirectory(originMetadata));
3450 QM_TRY_INSPECT(const bool& exists,
3451 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
3453 if (exists) {
3454 // Get the metadata. We only use the persisted flag.
3455 QM_TRY_INSPECT(const auto& metadata,
3456 aQuotaManager.LoadFullOriginMetadataWithRestore(directory));
3458 mPersisted = metadata.mPersisted;
3459 } else {
3460 // The directory has not been created yet.
3461 mPersisted = false;
3464 return NS_OK;
3467 void PersistedOp::GetResponse(RequestResponse& aResponse) {
3468 AssertIsOnOwningThread();
3470 PersistedResponse persistedResponse;
3471 persistedResponse.persisted() = mPersisted;
3473 aResponse = persistedResponse;
3476 PersistOp::PersistOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
3477 const RequestParams& aParams)
3478 : PersistRequestBase(std::move(aQuotaManager),
3479 aParams.get_PersistParams().principalInfo()) {
3480 MOZ_ASSERT(aParams.type() == RequestParams::TPersistParams);
3483 nsresult PersistOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
3484 AssertIsOnIOThread();
3485 aQuotaManager.AssertStorageIsInitializedInternal();
3487 const OriginMetadata originMetadata = {mPrincipalMetadata,
3488 PERSISTENCE_TYPE_DEFAULT};
3490 AUTO_PROFILER_LABEL("PersistOp::DoDirectoryWork", OTHER);
3492 // Update directory metadata on disk first. Then, create/update the
3493 // originInfo if needed.
3495 QM_TRY_INSPECT(const auto& directory,
3496 aQuotaManager.GetOriginDirectory(originMetadata));
3498 QM_TRY_INSPECT(const bool& created,
3499 aQuotaManager.EnsureOriginDirectory(*directory));
3501 if (created) {
3502 // A new origin directory has been created.
3504 // XXX The code below could be converted to a function which returns the
3505 // timestamp.
3506 int64_t timestamp;
3508 // Update OriginInfo too if temporary origin was already initialized.
3509 if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
3510 if (aQuotaManager.IsTemporaryOriginInitializedInternal(originMetadata)) {
3511 // We have a temporary origin which has been initialized without
3512 // ensuring respective origin directory. So OriginInfo already exists
3513 // and it needs to be updated because the origin directory has been
3514 // just created.
3516 timestamp = aQuotaManager.WithOriginInfo(
3517 originMetadata, [](const auto& originInfo) {
3518 const int64_t timestamp = originInfo->LockedAccessTime();
3520 originInfo->LockedDirectoryCreated();
3522 return timestamp;
3524 } else {
3525 timestamp = PR_Now();
3528 FullOriginMetadata fullOriginMetadata =
3529 FullOriginMetadata{originMetadata, /* aPersisted */ true, timestamp};
3531 // Usually, infallible operations are placed after fallible ones.
3532 // However, since we lack atomic support for creating the origin
3533 // directory along with its metadata, we need to add the origin to cached
3534 // origins right after directory creation.
3535 aQuotaManager.AddTemporaryOrigin(fullOriginMetadata);
3536 } else {
3537 timestamp = PR_Now();
3540 QM_TRY(MOZ_TO_RESULT(QuotaManager::CreateDirectoryMetadata2(
3541 *directory, timestamp, /* aPersisted */ true, originMetadata)));
3543 // Update or create OriginInfo too if temporary storage was already
3544 // initialized.
3545 if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
3546 if (aQuotaManager.IsTemporaryOriginInitializedInternal(originMetadata)) {
3547 // In this case, we have a temporary origin which has been initialized
3548 // without ensuring respective origin directory. So OriginInfo already
3549 // exists and it needs to be updated because the origin directory has
3550 // been just created.
3552 aQuotaManager.PersistOrigin(originMetadata);
3553 } else {
3554 // In this case, we have a temporary origin which hasn't been
3555 // initialized yet. So OriginInfo needs to be created because the
3556 // origin directory has been just created.
3558 FullOriginMetadata fullOriginMetadata = FullOriginMetadata{
3559 originMetadata, /* aPersisted */ true, timestamp};
3561 aQuotaManager.InitQuotaForOrigin(fullOriginMetadata, ClientUsageArray(),
3562 /* aUsageBytes */ 0);
3565 } else {
3566 QM_TRY_INSPECT(
3567 const bool& persisted,
3568 ([&aQuotaManager, &originMetadata,
3569 &directory]() -> mozilla::Result<bool, nsresult> {
3570 Nullable<bool> persisted =
3571 aQuotaManager.OriginPersisted(originMetadata);
3573 if (!persisted.IsNull()) {
3574 return persisted.Value();
3577 // Get the metadata (restore the metadata file if necessary). We only
3578 // use the persisted flag.
3579 QM_TRY_INSPECT(
3580 const auto& metadata,
3581 aQuotaManager.LoadFullOriginMetadataWithRestore(directory));
3583 return metadata.mPersisted;
3584 }()));
3586 if (!persisted) {
3587 QM_TRY_INSPECT(const auto& file,
3588 CloneFileAndAppend(
3589 *directory, nsLiteralString(METADATA_V2_FILE_NAME)));
3591 QM_TRY_INSPECT(const auto& stream,
3592 GetBinaryOutputStream(*file, FileFlag::Update));
3594 MOZ_ASSERT(stream);
3596 // Update origin access time while we are here.
3597 QM_TRY(MOZ_TO_RESULT(stream->Write64(PR_Now())));
3599 // Set the persisted flag to true.
3600 QM_TRY(MOZ_TO_RESULT(stream->WriteBoolean(true)));
3602 QM_TRY(MOZ_TO_RESULT(stream->Close()));
3604 // Directory metadata has been successfully updated.
3605 // Update OriginInfo too if temporary storage was already initialized.
3606 if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
3607 aQuotaManager.PersistOrigin(originMetadata);
3612 return NS_OK;
3615 void PersistOp::GetResponse(RequestResponse& aResponse) {
3616 AssertIsOnOwningThread();
3618 aResponse = PersistResponse();
3621 EstimateOp::EstimateOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
3622 const EstimateParams& aParams)
3623 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
3624 "dom::quota::EstimateOp"),
3625 mParams(aParams) {
3626 AssertIsOnOwningThread();
3629 nsresult EstimateOp::DoInit(QuotaManager& aQuotaManager) {
3630 AssertIsOnOwningThread();
3632 QM_TRY_UNWRAP(PrincipalMetadata principalMetadata,
3633 GetInfoFromValidatedPrincipalInfo(aQuotaManager,
3634 mParams.principalInfo()));
3636 principalMetadata.AssertInvariants();
3638 mOriginMetadata = {std::move(principalMetadata), PERSISTENCE_TYPE_DEFAULT};
3640 return NS_OK;
3643 RefPtr<BoolPromise> EstimateOp::OpenDirectory() {
3644 AssertIsOnOwningThread();
3646 return OpenStorageDirectory(
3647 PersistenceScope::CreateFromSet(PERSISTENCE_TYPE_TEMPORARY,
3648 PERSISTENCE_TYPE_DEFAULT,
3649 PERSISTENCE_TYPE_PRIVATE),
3650 OriginScope::FromGroup(mOriginMetadata.mGroup), Nullable<Client::Type>(),
3651 /* aExclusive */ false,
3652 /* aInitializeOrigins */ true);
3655 nsresult EstimateOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
3656 AssertIsOnIOThread();
3657 aQuotaManager.AssertStorageIsInitializedInternal();
3659 AUTO_PROFILER_LABEL("EstimateOp::DoDirectoryWork", OTHER);
3661 // Get cached usage (the method doesn't have to stat any files).
3662 mUsageAndLimit = aQuotaManager.GetUsageAndLimitForEstimate(mOriginMetadata);
3664 return NS_OK;
3667 void EstimateOp::GetResponse(RequestResponse& aResponse) {
3668 AssertIsOnOwningThread();
3670 EstimateResponse estimateResponse;
3672 estimateResponse.usage() = mUsageAndLimit.first;
3673 estimateResponse.limit() = mUsageAndLimit.second;
3675 aResponse = estimateResponse;
3678 void EstimateOp::CloseDirectory() {
3679 AssertIsOnOwningThread();
3681 SafeDropDirectoryLock(mDirectoryLock);
3684 ListOriginsOp::ListOriginsOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
3685 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
3686 "dom::quota::ListOriginsOp") {
3687 AssertIsOnOwningThread();
3690 RefPtr<BoolPromise> ListOriginsOp::OpenDirectory() {
3691 AssertIsOnOwningThread();
3693 return OpenStorageDirectory(PersistenceScope::CreateFromNull(),
3694 OriginScope::FromNull(), Nullable<Client::Type>(),
3695 /* aExclusive */ false);
3698 nsresult ListOriginsOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
3699 AssertIsOnIOThread();
3700 aQuotaManager.AssertStorageIsInitializedInternal();
3702 AUTO_PROFILER_LABEL("ListOriginsOp::DoDirectoryWork", OTHER);
3704 for (const PersistenceType type : kAllPersistenceTypes) {
3705 QM_TRY(MOZ_TO_RESULT(TraverseRepository(aQuotaManager, type)));
3708 // TraverseRepository above only consulted the file-system to get a list of
3709 // known origins, but we also need to include origins that have pending
3710 // quota usage.
3712 aQuotaManager.CollectPendingOriginsForListing([this](const auto& originInfo) {
3713 mOrigins.AppendElement(originInfo->Origin());
3716 return NS_OK;
3719 const Atomic<bool>& ListOriginsOp::GetIsCanceledFlag() {
3720 AssertIsOnIOThread();
3722 return Canceled();
3725 nsresult ListOriginsOp::ProcessOrigin(QuotaManager& aQuotaManager,
3726 nsIFile& aOriginDir,
3727 const bool aPersistent,
3728 const PersistenceType aPersistenceType) {
3729 AssertIsOnIOThread();
3731 QM_TRY_UNWRAP(auto maybeMetadata,
3732 QM_OR_ELSE_WARN_IF(
3733 // Expression
3734 aQuotaManager.GetOriginMetadata(&aOriginDir)
3735 .map([](auto metadata) -> Maybe<OriginMetadata> {
3736 return Some(std::move(metadata));
3738 // Predicate.
3739 IsSpecificError<NS_ERROR_MALFORMED_URI>,
3740 // Fallback.
3741 ErrToDefaultOk<Maybe<OriginMetadata>>));
3743 if (!maybeMetadata) {
3744 // Unknown directories during listing are allowed. Just warn if we find
3745 // them.
3746 QM_TRY_INSPECT(const auto& leafName,
3747 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, aOriginDir,
3748 GetLeafName));
3750 UNKNOWN_FILE_WARNING(leafName);
3751 return NS_OK;
3754 auto metadata = maybeMetadata.extract();
3756 if (aQuotaManager.IsOriginInternal(metadata.mOrigin)) {
3757 return NS_OK;
3760 mOrigins.AppendElement(std::move(metadata.mOrigin));
3762 return NS_OK;
3765 CStringArray ListOriginsOp::UnwrapResolveValue() {
3766 AssertIsOnOwningThread();
3767 MOZ_ASSERT(!ResolveValueConsumed());
3769 return std::move(mOrigins);
3772 void ListOriginsOp::CloseDirectory() {
3773 AssertIsOnOwningThread();
3775 SafeDropDirectoryLock(mDirectoryLock);
3778 } // namespace mozilla::dom::quota