Bug 1874684 - Part 6: Limit day length calculations to safe integers. r=mgaudet
[gecko.git] / dom / quota / OriginOperations.cpp
blob8eb6626780292096bad389dd7dcbd1eba29656d1
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/PersistenceType.h"
31 #include "mozilla/dom/quota/PQuota.h"
32 #include "mozilla/dom/quota/PQuotaRequest.h"
33 #include "mozilla/dom/quota/PQuotaUsageRequest.h"
34 #include "mozilla/dom/quota/OriginScope.h"
35 #include "mozilla/dom/quota/QuotaCommon.h"
36 #include "mozilla/dom/quota/QuotaManager.h"
37 #include "mozilla/dom/quota/QuotaManagerImpl.h"
38 #include "mozilla/dom/quota/ResultExtensions.h"
39 #include "mozilla/dom/quota/StreamUtils.h"
40 #include "mozilla/dom/quota/UsageInfo.h"
41 #include "mozilla/fallible.h"
42 #include "mozilla/ipc/BackgroundParent.h"
43 #include "mozilla/ipc/PBackgroundSharedTypes.h"
44 #include "NormalOriginOperationBase.h"
45 #include "nsCOMPtr.h"
46 #include "nsTHashMap.h"
47 #include "nsDebug.h"
48 #include "nsError.h"
49 #include "nsHashKeys.h"
50 #include "nsIBinaryOutputStream.h"
51 #include "nsIFile.h"
52 #include "nsIObjectOutputStream.h"
53 #include "nsIOutputStream.h"
54 #include "nsLiteralString.h"
55 #include "nsPrintfCString.h"
56 #include "nsString.h"
57 #include "nsTArray.h"
58 #include "OriginInfo.h"
59 #include "OriginOperationBase.h"
60 #include "QuotaRequestBase.h"
61 #include "QuotaUsageRequestBase.h"
62 #include "ResolvableNormalOriginOp.h"
63 #include "prthread.h"
64 #include "prtime.h"
66 namespace mozilla::dom::quota {
68 using namespace mozilla::ipc;
70 template <class Base>
71 class OpenStorageDirectoryHelper : public Base {
72 protected:
73 OpenStorageDirectoryHelper(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
74 const char* aName)
75 : Base(std::move(aQuotaManager), aName) {}
77 RefPtr<BoolPromise> OpenStorageDirectory(
78 const Nullable<PersistenceType>& aPersistenceType,
79 const OriginScope& aOriginScope,
80 const Nullable<Client::Type>& aClientType, bool aExclusive);
82 RefPtr<UniversalDirectoryLock> mDirectoryLock;
85 class FinalizeOriginEvictionOp : public OriginOperationBase {
86 nsTArray<RefPtr<OriginDirectoryLock>> mLocks;
88 public:
89 FinalizeOriginEvictionOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
90 nsTArray<RefPtr<OriginDirectoryLock>>&& aLocks)
91 : OriginOperationBase(std::move(aQuotaManager),
92 "dom::quota::FinalizeOriginEvictionOp"),
93 mLocks(std::move(aLocks)) {
94 AssertIsOnOwningThread();
97 private:
98 ~FinalizeOriginEvictionOp() = default;
100 virtual RefPtr<BoolPromise> Open() override;
102 virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
104 virtual void UnblockOpen() override;
107 class SaveOriginAccessTimeOp
108 : public OpenStorageDirectoryHelper<NormalOriginOperationBase> {
109 const OriginMetadata mOriginMetadata;
110 int64_t mTimestamp;
112 public:
113 SaveOriginAccessTimeOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
114 const OriginMetadata& aOriginMetadata,
115 int64_t aTimestamp)
116 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
117 "dom::quota::SaveOriginAccessTimeOp"),
118 mOriginMetadata(aOriginMetadata),
119 mTimestamp(aTimestamp) {
120 AssertIsOnOwningThread();
123 private:
124 ~SaveOriginAccessTimeOp() = default;
126 RefPtr<BoolPromise> OpenDirectory() override;
128 virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
130 virtual void SendResults() override;
132 void CloseDirectory() override;
135 class ClearPrivateRepositoryOp
136 : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<bool>> {
137 public:
138 explicit ClearPrivateRepositoryOp(
139 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
140 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
141 "dom::quota::ClearPrivateRepositoryOp") {
142 AssertIsOnOwningThread();
145 private:
146 ~ClearPrivateRepositoryOp() = default;
148 RefPtr<BoolPromise> OpenDirectory() override;
150 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
152 bool GetResolveValue() override { return true; }
154 void CloseDirectory() override;
157 class ShutdownStorageOp : public ResolvableNormalOriginOp<bool> {
158 RefPtr<UniversalDirectoryLock> mDirectoryLock;
160 public:
161 explicit ShutdownStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
162 : ResolvableNormalOriginOp(std::move(aQuotaManager),
163 "dom::quota::ShutdownStorageOp") {
164 AssertIsOnOwningThread();
167 private:
168 ~ShutdownStorageOp() = default;
170 #ifdef DEBUG
171 nsresult DirectoryOpen() override;
172 #endif
174 RefPtr<BoolPromise> OpenDirectory() override;
176 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
178 bool GetResolveValue() override { return true; }
180 void CloseDirectory() override;
183 // A mix-in class to simplify operations that need to process every origin in
184 // one or more repositories. Sub-classes should call TraverseRepository in their
185 // DoDirectoryWork and implement a ProcessOrigin method for their per-origin
186 // logic.
187 class TraverseRepositoryHelper {
188 public:
189 TraverseRepositoryHelper() = default;
191 protected:
192 virtual ~TraverseRepositoryHelper() = default;
194 // If ProcessOrigin returns an error, TraverseRepository will immediately
195 // terminate and return the received error code to its caller.
196 nsresult TraverseRepository(QuotaManager& aQuotaManager,
197 PersistenceType aPersistenceType);
199 private:
200 virtual const Atomic<bool>& GetIsCanceledFlag() = 0;
202 virtual nsresult ProcessOrigin(QuotaManager& aQuotaManager,
203 nsIFile& aOriginDir, const bool aPersistent,
204 const PersistenceType aPersistenceType) = 0;
207 class GetUsageOp final
208 : public OpenStorageDirectoryHelper<QuotaUsageRequestBase>,
209 public TraverseRepositoryHelper {
210 nsTArray<OriginUsage> mOriginUsages;
211 nsTHashMap<nsCStringHashKey, uint32_t> mOriginUsagesIndex;
213 bool mGetAll;
215 public:
216 GetUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
217 const UsageRequestParams& aParams);
219 private:
220 ~GetUsageOp() = default;
222 void ProcessOriginInternal(QuotaManager* aQuotaManager,
223 const PersistenceType aPersistenceType,
224 const nsACString& aOrigin,
225 const int64_t aTimestamp, const bool aPersisted,
226 const uint64_t aUsage);
228 RefPtr<BoolPromise> OpenDirectory() override;
230 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
232 const Atomic<bool>& GetIsCanceledFlag() override;
234 nsresult ProcessOrigin(QuotaManager& aQuotaManager, nsIFile& aOriginDir,
235 const bool aPersistent,
236 const PersistenceType aPersistenceType) override;
238 void GetResponse(UsageRequestResponse& aResponse) override;
240 void CloseDirectory() override;
243 class GetOriginUsageOp final
244 : public OpenStorageDirectoryHelper<QuotaUsageRequestBase> {
245 const OriginUsageParams mParams;
246 PrincipalMetadata mPrincipalMetadata;
247 UsageInfo mUsageInfo;
248 bool mFromMemory;
250 public:
251 GetOriginUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
252 const UsageRequestParams& aParams);
254 private:
255 ~GetOriginUsageOp() = default;
257 nsresult DoInit(QuotaManager& aQuotaManager) override;
259 RefPtr<BoolPromise> OpenDirectory() override;
261 virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
263 void GetResponse(UsageRequestResponse& aResponse) override;
265 void CloseDirectory() override;
268 class StorageNameOp final : public QuotaRequestBase {
269 nsString mName;
271 public:
272 explicit StorageNameOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
274 private:
275 ~StorageNameOp() = default;
277 RefPtr<BoolPromise> OpenDirectory() override;
279 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
281 void GetResponse(RequestResponse& aResponse) override;
283 void CloseDirectory() override;
286 class InitializedRequestBase : public ResolvableNormalOriginOp<bool> {
287 protected:
288 bool mInitialized;
290 InitializedRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
291 const char* aName);
293 private:
294 RefPtr<BoolPromise> OpenDirectory() override;
296 void CloseDirectory() override;
299 class StorageInitializedOp final : public InitializedRequestBase {
300 public:
301 explicit StorageInitializedOp(
302 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
303 : InitializedRequestBase(std::move(aQuotaManager),
304 "dom::quota::StorageInitializedOp") {}
306 private:
307 ~StorageInitializedOp() = default;
309 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
311 bool GetResolveValue() override;
314 class TemporaryStorageInitializedOp final : public InitializedRequestBase {
315 public:
316 explicit TemporaryStorageInitializedOp(
317 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
318 : InitializedRequestBase(std::move(aQuotaManager),
319 "dom::quota::StorageInitializedOp") {}
321 private:
322 ~TemporaryStorageInitializedOp() = default;
324 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
326 bool GetResolveValue() override;
329 class InitOp final : public ResolvableNormalOriginOp<bool> {
330 RefPtr<UniversalDirectoryLock> mDirectoryLock;
332 public:
333 InitOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
334 RefPtr<UniversalDirectoryLock> aDirectoryLock);
336 private:
337 ~InitOp() = default;
339 RefPtr<BoolPromise> OpenDirectory() override;
341 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
343 bool GetResolveValue() override;
345 void CloseDirectory() override;
348 class InitTemporaryStorageOp final : public ResolvableNormalOriginOp<bool> {
349 RefPtr<UniversalDirectoryLock> mDirectoryLock;
351 public:
352 InitTemporaryStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
353 RefPtr<UniversalDirectoryLock> aDirectoryLock);
355 private:
356 ~InitTemporaryStorageOp() = default;
358 RefPtr<BoolPromise> OpenDirectory() override;
360 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
362 bool GetResolveValue() override;
364 void CloseDirectory() override;
367 class InitializeOriginRequestBase : public QuotaRequestBase {
368 protected:
369 const PrincipalInfo mPrincipalInfo;
370 PrincipalMetadata mPrincipalMetadata;
371 RefPtr<UniversalDirectoryLock> mDirectoryLock;
372 const PersistenceType mPersistenceType;
373 bool mCreated;
375 InitializeOriginRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
376 const char* aName,
377 PersistenceType aPersistenceType,
378 const PrincipalInfo& aPrincipalInfo);
380 nsresult DoInit(QuotaManager& aQuotaManager) override;
382 private:
383 RefPtr<BoolPromise> OpenDirectory() override;
385 void CloseDirectory() override;
388 class InitializePersistentOriginOp final : public InitializeOriginRequestBase {
389 public:
390 InitializePersistentOriginOp(
391 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
392 const RequestParams& aParams);
394 private:
395 ~InitializePersistentOriginOp() = default;
397 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
399 void GetResponse(RequestResponse& aResponse) override;
402 class InitializeTemporaryOriginOp final : public InitializeOriginRequestBase {
403 public:
404 InitializeTemporaryOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
405 const RequestParams& aParams);
407 private:
408 ~InitializeTemporaryOriginOp() = default;
410 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
412 void GetResponse(RequestResponse& aResponse) override;
415 class InitializeClientBase : public ResolvableNormalOriginOp<bool> {
416 protected:
417 const PrincipalInfo mPrincipalInfo;
418 ClientMetadata mClientMetadata;
419 RefPtr<UniversalDirectoryLock> mDirectoryLock;
420 const PersistenceType mPersistenceType;
421 const Client::Type mClientType;
422 bool mCreated;
424 InitializeClientBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
425 const char* aName, PersistenceType aPersistenceType,
426 const PrincipalInfo& aPrincipalInfo,
427 Client::Type aClientType);
429 nsresult DoInit(QuotaManager& aQuotaManager) override;
431 private:
432 RefPtr<BoolPromise> OpenDirectory() override;
434 void CloseDirectory() override;
437 class InitializePersistentClientOp : public InitializeClientBase {
438 public:
439 InitializePersistentClientOp(
440 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
441 const PrincipalInfo& aPrincipalInfo, Client::Type aClientType);
443 private:
444 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
446 bool GetResolveValue() override;
449 class InitializeTemporaryClientOp : public InitializeClientBase {
450 public:
451 InitializeTemporaryClientOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
452 PersistenceType aPersistenceType,
453 const PrincipalInfo& aPrincipalInfo,
454 Client::Type aClientType);
456 private:
457 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
459 bool GetResolveValue() override;
462 class GetFullOriginMetadataOp
463 : public OpenStorageDirectoryHelper<QuotaRequestBase> {
464 const GetFullOriginMetadataParams mParams;
465 // XXX Consider wrapping with LazyInitializedOnce
466 OriginMetadata mOriginMetadata;
467 Maybe<FullOriginMetadata> mMaybeFullOriginMetadata;
469 public:
470 GetFullOriginMetadataOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
471 const GetFullOriginMetadataParams& aParams);
473 private:
474 nsresult DoInit(QuotaManager& aQuotaManager) override;
476 RefPtr<BoolPromise> OpenDirectory() override;
478 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
480 void GetResponse(RequestResponse& aResponse) override;
482 void CloseDirectory() override;
485 class ClearStorageOp final
486 : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<bool>> {
487 public:
488 explicit ClearStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
490 private:
491 ~ClearStorageOp() = default;
493 void DeleteFiles(QuotaManager& aQuotaManager);
495 void DeleteStorageFile(QuotaManager& aQuotaManager);
497 RefPtr<BoolPromise> OpenDirectory() override;
499 virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
501 bool GetResolveValue() override;
503 void CloseDirectory() override;
506 class ClearRequestBase
507 : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<bool>> {
508 protected:
509 ClearRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
510 const char* aName)
511 : OpenStorageDirectoryHelper(std::move(aQuotaManager), aName) {
512 AssertIsOnOwningThread();
515 void DeleteFiles(QuotaManager& aQuotaManager,
516 const OriginMetadata& aOriginMetadata,
517 const Nullable<Client::Type>& aClientType);
519 void DeleteFiles(QuotaManager& aQuotaManager,
520 PersistenceType aPersistenceType,
521 const OriginScope& aOriginScope,
522 const Nullable<Client::Type>& aClientType);
524 private:
525 template <typename FileCollector>
526 void DeleteFilesInternal(QuotaManager& aQuotaManager,
527 PersistenceType aPersistenceType,
528 const OriginScope& aOriginScope,
529 const Nullable<Client::Type>& aClientType,
530 const FileCollector& aFileCollector);
533 class ClearOriginOp final : public ClearRequestBase {
534 const PrincipalInfo mPrincipalInfo;
535 PrincipalMetadata mPrincipalMetadata;
536 const Nullable<PersistenceType> mPersistenceType;
537 const Nullable<Client::Type> mClientType;
539 public:
540 ClearOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
541 const mozilla::Maybe<PersistenceType>& aPersistenceType,
542 const PrincipalInfo& aPrincipalInfo,
543 const mozilla::Maybe<Client::Type>& aClientType);
545 private:
546 ~ClearOriginOp() = default;
548 nsresult DoInit(QuotaManager& aQuotaManager) override;
550 RefPtr<BoolPromise> OpenDirectory() override;
552 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
554 bool GetResolveValue() override;
556 void CloseDirectory() override;
559 class ClearStoragesForOriginPrefixOp final
560 : public OpenStorageDirectoryHelper<ClearRequestBase> {
561 const nsCString mPrefix;
562 const Nullable<PersistenceType> mPersistenceType;
564 public:
565 ClearStoragesForOriginPrefixOp(
566 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
567 const Maybe<PersistenceType>& aPersistenceType,
568 const PrincipalInfo& aPrincipalInfo);
570 private:
571 ~ClearStoragesForOriginPrefixOp() = default;
573 RefPtr<BoolPromise> OpenDirectory() override;
575 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
577 bool GetResolveValue() override;
579 void CloseDirectory() override;
582 class ClearDataOp final : public ClearRequestBase {
583 const OriginAttributesPattern mPattern;
585 public:
586 ClearDataOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
587 const OriginAttributesPattern& aPattern);
589 private:
590 ~ClearDataOp() = default;
592 RefPtr<BoolPromise> OpenDirectory() override;
594 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
596 bool GetResolveValue() override;
598 void CloseDirectory() override;
601 class ResetOriginOp final : public QuotaRequestBase {
602 nsCString mOrigin;
603 RefPtr<UniversalDirectoryLock> mDirectoryLock;
604 Nullable<PersistenceType> mPersistenceType;
605 Nullable<Client::Type> mClientType;
607 public:
608 ResetOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
609 const RequestParams& aParams);
611 private:
612 ~ResetOriginOp() = default;
614 RefPtr<BoolPromise> OpenDirectory() override;
616 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
618 void GetResponse(RequestResponse& aResponse) override;
620 void CloseDirectory() override;
623 class PersistRequestBase : public OpenStorageDirectoryHelper<QuotaRequestBase> {
624 const PrincipalInfo mPrincipalInfo;
626 protected:
627 PrincipalMetadata mPrincipalMetadata;
629 protected:
630 PersistRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
631 const PrincipalInfo& aPrincipalInfo);
633 nsresult DoInit(QuotaManager& aQuotaManager) override;
635 private:
636 RefPtr<BoolPromise> OpenDirectory() override;
638 void CloseDirectory() override;
641 class PersistedOp final : public PersistRequestBase {
642 bool mPersisted;
644 public:
645 PersistedOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
646 const RequestParams& aParams);
648 private:
649 ~PersistedOp() = default;
651 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
653 void GetResponse(RequestResponse& aResponse) override;
656 class PersistOp final : public PersistRequestBase {
657 public:
658 PersistOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
659 const RequestParams& aParams);
661 private:
662 ~PersistOp() = default;
664 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
666 void GetResponse(RequestResponse& aResponse) override;
669 class EstimateOp final : public OpenStorageDirectoryHelper<QuotaRequestBase> {
670 const EstimateParams mParams;
671 OriginMetadata mOriginMetadata;
672 std::pair<uint64_t, uint64_t> mUsageAndLimit;
674 public:
675 EstimateOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
676 const EstimateParams& aParams);
678 private:
679 ~EstimateOp() = default;
681 nsresult DoInit(QuotaManager& aQuotaManager) override;
683 RefPtr<BoolPromise> OpenDirectory() override;
685 virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
687 void GetResponse(RequestResponse& aResponse) override;
689 void CloseDirectory() override;
692 class ListOriginsOp final : public OpenStorageDirectoryHelper<QuotaRequestBase>,
693 public TraverseRepositoryHelper {
694 // XXX Bug 1521541 will make each origin has it's own state.
695 nsTArray<nsCString> mOrigins;
697 public:
698 explicit ListOriginsOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
700 private:
701 ~ListOriginsOp() = default;
703 RefPtr<BoolPromise> OpenDirectory() override;
705 nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
707 const Atomic<bool>& GetIsCanceledFlag() override;
709 nsresult ProcessOrigin(QuotaManager& aQuotaManager, nsIFile& aOriginDir,
710 const bool aPersistent,
711 const PersistenceType aPersistenceType) override;
713 void GetResponse(RequestResponse& aResponse) override;
715 void CloseDirectory() override;
718 RefPtr<OriginOperationBase> CreateFinalizeOriginEvictionOp(
719 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
720 nsTArray<RefPtr<OriginDirectoryLock>>&& aLocks) {
721 return MakeRefPtr<FinalizeOriginEvictionOp>(std::move(aQuotaManager),
722 std::move(aLocks));
725 RefPtr<NormalOriginOperationBase> CreateSaveOriginAccessTimeOp(
726 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
727 const OriginMetadata& aOriginMetadata, int64_t aTimestamp) {
728 return MakeRefPtr<SaveOriginAccessTimeOp>(std::move(aQuotaManager),
729 aOriginMetadata, aTimestamp);
732 RefPtr<ResolvableNormalOriginOp<bool>> CreateClearPrivateRepositoryOp(
733 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
734 return MakeRefPtr<ClearPrivateRepositoryOp>(std::move(aQuotaManager));
737 RefPtr<ResolvableNormalOriginOp<bool>> CreateShutdownStorageOp(
738 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
739 return MakeRefPtr<ShutdownStorageOp>(std::move(aQuotaManager));
742 RefPtr<QuotaUsageRequestBase> CreateGetUsageOp(
743 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
744 const UsageRequestParams& aParams) {
745 return MakeRefPtr<GetUsageOp>(std::move(aQuotaManager), aParams);
748 RefPtr<QuotaUsageRequestBase> CreateGetOriginUsageOp(
749 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
750 const UsageRequestParams& aParams) {
751 return MakeRefPtr<GetOriginUsageOp>(std::move(aQuotaManager), aParams);
754 RefPtr<QuotaRequestBase> CreateStorageNameOp(
755 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
756 return MakeRefPtr<StorageNameOp>(std::move(aQuotaManager));
759 RefPtr<ResolvableNormalOriginOp<bool>> CreateStorageInitializedOp(
760 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
761 return MakeRefPtr<StorageInitializedOp>(std::move(aQuotaManager));
764 RefPtr<ResolvableNormalOriginOp<bool>> CreateTemporaryStorageInitializedOp(
765 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
766 return MakeRefPtr<TemporaryStorageInitializedOp>(std::move(aQuotaManager));
769 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitOp(
770 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
771 RefPtr<UniversalDirectoryLock> aDirectoryLock) {
772 return MakeRefPtr<InitOp>(std::move(aQuotaManager),
773 std::move(aDirectoryLock));
776 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitTemporaryStorageOp(
777 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
778 RefPtr<UniversalDirectoryLock> aDirectoryLock) {
779 return MakeRefPtr<InitTemporaryStorageOp>(std::move(aQuotaManager),
780 std::move(aDirectoryLock));
783 RefPtr<QuotaRequestBase> CreateInitializePersistentOriginOp(
784 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
785 const RequestParams& aParams) {
786 return MakeRefPtr<InitializePersistentOriginOp>(std::move(aQuotaManager),
787 aParams);
790 RefPtr<QuotaRequestBase> CreateInitializeTemporaryOriginOp(
791 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
792 const RequestParams& aParams) {
793 return MakeRefPtr<InitializeTemporaryOriginOp>(std::move(aQuotaManager),
794 aParams);
797 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializePersistentClientOp(
798 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
799 const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
800 const Client::Type aClientType) {
801 return MakeRefPtr<InitializePersistentClientOp>(std::move(aQuotaManager),
802 aPrincipalInfo, aClientType);
805 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializeTemporaryClientOp(
806 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
807 const PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
808 const Client::Type aClientType) {
809 return MakeRefPtr<InitializeTemporaryClientOp>(
810 std::move(aQuotaManager), aPersistenceType, aPrincipalInfo, aClientType);
813 RefPtr<QuotaRequestBase> CreateGetFullOriginMetadataOp(
814 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
815 const GetFullOriginMetadataParams& aParams) {
816 return MakeRefPtr<GetFullOriginMetadataOp>(std::move(aQuotaManager), aParams);
819 RefPtr<ResolvableNormalOriginOp<bool>> CreateClearStorageOp(
820 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
821 return MakeRefPtr<ClearStorageOp>(std::move(aQuotaManager));
824 RefPtr<ResolvableNormalOriginOp<bool>> CreateClearOriginOp(
825 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
826 const Maybe<PersistenceType>& aPersistenceType,
827 const PrincipalInfo& aPrincipalInfo,
828 const Maybe<Client::Type>& aClientType) {
829 return MakeRefPtr<ClearOriginOp>(std::move(aQuotaManager), aPersistenceType,
830 aPrincipalInfo, aClientType);
833 RefPtr<ResolvableNormalOriginOp<bool>> CreateClearStoragesForOriginPrefixOp(
834 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
835 const Maybe<PersistenceType>& aPersistenceType,
836 const PrincipalInfo& aPrincipalInfo) {
837 return MakeRefPtr<ClearStoragesForOriginPrefixOp>(
838 std::move(aQuotaManager), aPersistenceType, aPrincipalInfo);
841 RefPtr<ResolvableNormalOriginOp<bool>> CreateClearDataOp(
842 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
843 const OriginAttributesPattern& aPattern) {
844 return MakeRefPtr<ClearDataOp>(std::move(aQuotaManager), aPattern);
847 RefPtr<QuotaRequestBase> CreateResetOriginOp(
848 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
849 const RequestParams& aParams) {
850 return MakeRefPtr<ResetOriginOp>(std::move(aQuotaManager), aParams);
853 RefPtr<QuotaRequestBase> CreatePersistedOp(
854 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
855 const RequestParams& aParams) {
856 return MakeRefPtr<PersistedOp>(std::move(aQuotaManager), aParams);
859 RefPtr<QuotaRequestBase> CreatePersistOp(
860 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
861 const RequestParams& aParams) {
862 return MakeRefPtr<PersistOp>(std::move(aQuotaManager), aParams);
865 RefPtr<QuotaRequestBase> CreateEstimateOp(
866 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
867 const EstimateParams& aParams) {
868 return MakeRefPtr<EstimateOp>(std::move(aQuotaManager), aParams);
871 RefPtr<QuotaRequestBase> CreateListOriginsOp(
872 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
873 return MakeRefPtr<ListOriginsOp>(std::move(aQuotaManager));
876 template <class Base>
877 RefPtr<BoolPromise> OpenStorageDirectoryHelper<Base>::OpenStorageDirectory(
878 const Nullable<PersistenceType>& aPersistenceType,
879 const OriginScope& aOriginScope, const Nullable<Client::Type>& aClientType,
880 bool aExclusive) {
881 return Base::mQuotaManager
882 ->OpenStorageDirectory(aPersistenceType, aOriginScope, aClientType,
883 aExclusive)
884 ->Then(GetCurrentSerialEventTarget(), __func__,
885 [self = RefPtr(this)](
886 UniversalDirectoryLockPromise::ResolveOrRejectValue&& aValue) {
887 if (aValue.IsReject()) {
888 return BoolPromise::CreateAndReject(aValue.RejectValue(),
889 __func__);
892 self->mDirectoryLock = std::move(aValue.ResolveValue());
894 return BoolPromise::CreateAndResolve(true, __func__);
898 RefPtr<BoolPromise> FinalizeOriginEvictionOp::Open() {
899 AssertIsOnOwningThread();
900 MOZ_ASSERT(!mLocks.IsEmpty());
902 return BoolPromise::CreateAndResolve(true, __func__);
905 nsresult FinalizeOriginEvictionOp::DoDirectoryWork(
906 QuotaManager& aQuotaManager) {
907 AssertIsOnIOThread();
909 AUTO_PROFILER_LABEL("FinalizeOriginEvictionOp::DoDirectoryWork", OTHER);
911 for (const auto& lock : mLocks) {
912 aQuotaManager.OriginClearCompleted(
913 lock->GetPersistenceType(), lock->Origin(), Nullable<Client::Type>());
916 return NS_OK;
919 void FinalizeOriginEvictionOp::UnblockOpen() {
920 AssertIsOnOwningThread();
922 #ifdef DEBUG
923 NoteActorDestroyed();
924 #endif
926 mLocks.Clear();
929 RefPtr<BoolPromise> SaveOriginAccessTimeOp::OpenDirectory() {
930 AssertIsOnOwningThread();
932 return OpenStorageDirectory(
933 Nullable<PersistenceType>(mOriginMetadata.mPersistenceType),
934 OriginScope::FromOrigin(mOriginMetadata.mOrigin),
935 Nullable<Client::Type>(),
936 /* aExclusive */ false);
939 nsresult SaveOriginAccessTimeOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
940 AssertIsOnIOThread();
941 aQuotaManager.AssertStorageIsInitializedInternal();
943 AUTO_PROFILER_LABEL("SaveOriginAccessTimeOp::DoDirectoryWork", OTHER);
945 QM_TRY(MOZ_TO_RESULT(!QuotaManager::IsShuttingDown()), NS_ERROR_ABORT);
947 QM_TRY_INSPECT(const auto& file,
948 aQuotaManager.GetOriginDirectory(mOriginMetadata));
950 // The origin directory might not exist
951 // anymore, because it was deleted by a clear operation.
952 QM_TRY_INSPECT(const bool& exists, MOZ_TO_RESULT_INVOKE_MEMBER(file, Exists));
954 if (exists) {
955 QM_TRY(MOZ_TO_RESULT(file->Append(nsLiteralString(METADATA_V2_FILE_NAME))));
957 QM_TRY_INSPECT(const auto& stream,
958 GetBinaryOutputStream(*file, FileFlag::Update));
959 MOZ_ASSERT(stream);
961 QM_TRY(MOZ_TO_RESULT(stream->Write64(mTimestamp)));
964 return NS_OK;
967 void SaveOriginAccessTimeOp::SendResults() {
968 #ifdef DEBUG
969 NoteActorDestroyed();
970 #endif
973 void SaveOriginAccessTimeOp::CloseDirectory() {
974 AssertIsOnOwningThread();
976 mDirectoryLock = nullptr;
979 RefPtr<BoolPromise> ClearPrivateRepositoryOp::OpenDirectory() {
980 AssertIsOnOwningThread();
982 return OpenStorageDirectory(
983 Nullable<PersistenceType>(PERSISTENCE_TYPE_PRIVATE),
984 OriginScope::FromNull(), Nullable<Client::Type>(),
985 /* aExclusive */ true);
988 nsresult ClearPrivateRepositoryOp::DoDirectoryWork(
989 QuotaManager& aQuotaManager) {
990 AssertIsOnIOThread();
991 aQuotaManager.AssertStorageIsInitializedInternal();
993 AUTO_PROFILER_LABEL("ClearPrivateRepositoryOp::DoDirectoryWork", OTHER);
995 QM_TRY_INSPECT(
996 const auto& directory,
997 QM_NewLocalFile(aQuotaManager.GetStoragePath(PERSISTENCE_TYPE_PRIVATE)));
999 nsresult rv = directory->Remove(true);
1000 if (rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
1001 // This should never fail if we've closed all storage connections
1002 // correctly...
1003 MOZ_ASSERT(false, "Failed to remove directory!");
1006 aQuotaManager.RemoveQuotaForRepository(PERSISTENCE_TYPE_PRIVATE);
1008 aQuotaManager.RepositoryClearCompleted(PERSISTENCE_TYPE_PRIVATE);
1010 return NS_OK;
1013 void ClearPrivateRepositoryOp::CloseDirectory() {
1014 AssertIsOnOwningThread();
1016 mDirectoryLock = nullptr;
1019 RefPtr<BoolPromise> ShutdownStorageOp::OpenDirectory() {
1020 AssertIsOnOwningThread();
1022 // Clear directory lock tables (which also saves origin access time) before
1023 // acquiring the exclusive lock below. Otherwise, saving of origin access
1024 // time would be scheduled after storage shutdown and that would initialize
1025 // storage again in the end.
1026 mQuotaManager->ClearDirectoryLockTables();
1028 mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
1029 Nullable<PersistenceType>(), OriginScope::FromNull(),
1030 Nullable<Client::Type>(),
1031 /* aExclusive */ true);
1033 return mDirectoryLock->Acquire();
1036 #ifdef DEBUG
1037 nsresult ShutdownStorageOp::DirectoryOpen() {
1038 AssertIsOnBackgroundThread();
1039 MOZ_ASSERT(mDirectoryLock);
1040 mDirectoryLock->AssertIsAcquiredExclusively();
1042 return NormalOriginOperationBase::DirectoryOpen();
1044 #endif
1046 nsresult ShutdownStorageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1047 AssertIsOnIOThread();
1049 AUTO_PROFILER_LABEL("ShutdownStorageOp::DoDirectoryWork", OTHER);
1051 aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
1052 "ShutdownStorageOp::DoDirectoryWork -> ShutdownStorageInternal."_ns);
1054 aQuotaManager.ShutdownStorageInternal();
1056 return NS_OK;
1059 void ShutdownStorageOp::CloseDirectory() {
1060 AssertIsOnOwningThread();
1062 mDirectoryLock = nullptr;
1065 nsresult TraverseRepositoryHelper::TraverseRepository(
1066 QuotaManager& aQuotaManager, PersistenceType aPersistenceType) {
1067 AssertIsOnIOThread();
1069 QM_TRY_INSPECT(
1070 const auto& directory,
1071 QM_NewLocalFile(aQuotaManager.GetStoragePath(aPersistenceType)));
1073 QM_TRY_INSPECT(const bool& exists,
1074 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
1076 if (!exists) {
1077 return NS_OK;
1080 QM_TRY(CollectEachFileAtomicCancelable(
1081 *directory, GetIsCanceledFlag(),
1082 [this, aPersistenceType, &aQuotaManager,
1083 persistent = aPersistenceType == PERSISTENCE_TYPE_PERSISTENT](
1084 const nsCOMPtr<nsIFile>& originDir) -> Result<Ok, nsresult> {
1085 QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*originDir));
1087 switch (dirEntryKind) {
1088 case nsIFileKind::ExistsAsDirectory:
1089 QM_TRY(MOZ_TO_RESULT(ProcessOrigin(aQuotaManager, *originDir,
1090 persistent, aPersistenceType)));
1091 break;
1093 case nsIFileKind::ExistsAsFile: {
1094 QM_TRY_INSPECT(const auto& leafName,
1095 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
1096 nsAutoString, originDir, GetLeafName));
1098 // Unknown files during getting usages are allowed. Just warn if we
1099 // find them.
1100 if (!IsOSMetadata(leafName)) {
1101 UNKNOWN_FILE_WARNING(leafName);
1104 break;
1107 case nsIFileKind::DoesNotExist:
1108 // Ignore files that got removed externally while iterating.
1109 break;
1112 return Ok{};
1113 }));
1115 return NS_OK;
1118 GetUsageOp::GetUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1119 const UsageRequestParams& aParams)
1120 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
1121 "dom::quota::GetUsageOp"),
1122 mGetAll(aParams.get_AllUsageParams().getAll()) {
1123 AssertIsOnOwningThread();
1124 MOZ_ASSERT(aParams.type() == UsageRequestParams::TAllUsageParams);
1127 void GetUsageOp::ProcessOriginInternal(QuotaManager* aQuotaManager,
1128 const PersistenceType aPersistenceType,
1129 const nsACString& aOrigin,
1130 const int64_t aTimestamp,
1131 const bool aPersisted,
1132 const uint64_t aUsage) {
1133 if (!mGetAll && aQuotaManager->IsOriginInternal(aOrigin)) {
1134 return;
1137 // We can't store pointers to OriginUsage objects in the hashtable
1138 // since AppendElement() reallocates its internal array buffer as number
1139 // of elements grows.
1140 const auto& originUsage =
1141 mOriginUsagesIndex.WithEntryHandle(aOrigin, [&](auto&& entry) {
1142 if (entry) {
1143 return WrapNotNullUnchecked(&mOriginUsages[entry.Data()]);
1146 entry.Insert(mOriginUsages.Length());
1148 return mOriginUsages.EmplaceBack(nsCString{aOrigin}, false, 0, 0);
1151 if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) {
1152 originUsage->persisted() = aPersisted;
1155 originUsage->usage() = originUsage->usage() + aUsage;
1157 originUsage->lastAccessed() =
1158 std::max<int64_t>(originUsage->lastAccessed(), aTimestamp);
1161 const Atomic<bool>& GetUsageOp::GetIsCanceledFlag() {
1162 AssertIsOnIOThread();
1164 return mCanceled;
1167 // XXX Remove aPersistent
1168 // XXX Remove aPersistenceType once GetUsageForOrigin uses the persistence
1169 // type from OriginMetadata
1170 nsresult GetUsageOp::ProcessOrigin(QuotaManager& aQuotaManager,
1171 nsIFile& aOriginDir, const bool aPersistent,
1172 const PersistenceType aPersistenceType) {
1173 AssertIsOnIOThread();
1175 QM_TRY_UNWRAP(auto maybeMetadata,
1176 QM_OR_ELSE_WARN_IF(
1177 // Expression
1178 aQuotaManager.LoadFullOriginMetadataWithRestore(&aOriginDir)
1179 .map([](auto metadata) -> Maybe<FullOriginMetadata> {
1180 return Some(std::move(metadata));
1182 // Predicate.
1183 IsSpecificError<NS_ERROR_MALFORMED_URI>,
1184 // Fallback.
1185 ErrToDefaultOk<Maybe<FullOriginMetadata>>));
1187 if (!maybeMetadata) {
1188 // Unknown directories during getting usage are allowed. Just warn if we
1189 // find them.
1190 QM_TRY_INSPECT(const auto& leafName,
1191 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, aOriginDir,
1192 GetLeafName));
1194 UNKNOWN_FILE_WARNING(leafName);
1195 return NS_OK;
1198 auto metadata = maybeMetadata.extract();
1200 QM_TRY_INSPECT(const auto& usageInfo,
1201 GetUsageForOrigin(aQuotaManager, aPersistenceType, metadata));
1203 ProcessOriginInternal(&aQuotaManager, aPersistenceType, metadata.mOrigin,
1204 metadata.mLastAccessTime, metadata.mPersisted,
1205 usageInfo.TotalUsage().valueOr(0));
1207 return NS_OK;
1210 RefPtr<BoolPromise> GetUsageOp::OpenDirectory() {
1211 AssertIsOnOwningThread();
1213 return OpenStorageDirectory(Nullable<PersistenceType>(),
1214 OriginScope::FromNull(), Nullable<Client::Type>(),
1215 /* aExclusive */ false);
1218 nsresult GetUsageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1219 AssertIsOnIOThread();
1220 aQuotaManager.AssertStorageIsInitializedInternal();
1222 AUTO_PROFILER_LABEL("GetUsageOp::DoDirectoryWork", OTHER);
1224 nsresult rv;
1226 for (const PersistenceType type : kAllPersistenceTypes) {
1227 rv = TraverseRepository(aQuotaManager, type);
1228 if (NS_WARN_IF(NS_FAILED(rv))) {
1229 return rv;
1233 // TraverseRepository above only consulted the filesystem. We also need to
1234 // consider origins which may have pending quota usage, such as buffered
1235 // LocalStorage writes for an origin which didn't previously have any
1236 // LocalStorage data.
1238 aQuotaManager.CollectPendingOriginsForListing(
1239 [this, &aQuotaManager](const auto& originInfo) {
1240 ProcessOriginInternal(
1241 &aQuotaManager, originInfo->GetGroupInfo()->GetPersistenceType(),
1242 originInfo->Origin(), originInfo->LockedAccessTime(),
1243 originInfo->LockedPersisted(), originInfo->LockedUsage());
1246 return NS_OK;
1249 void GetUsageOp::GetResponse(UsageRequestResponse& aResponse) {
1250 AssertIsOnOwningThread();
1252 aResponse = AllUsageResponse();
1254 aResponse.get_AllUsageResponse().originUsages() = std::move(mOriginUsages);
1257 void GetUsageOp::CloseDirectory() {
1258 AssertIsOnOwningThread();
1260 mDirectoryLock = nullptr;
1263 GetOriginUsageOp::GetOriginUsageOp(
1264 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1265 const UsageRequestParams& aParams)
1266 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
1267 "dom::quota::GetOriginUsageOp"),
1268 mParams(aParams.get_OriginUsageParams()) {
1269 AssertIsOnOwningThread();
1270 MOZ_ASSERT(aParams.type() == UsageRequestParams::TOriginUsageParams);
1272 // Overwrite GetOriginUsageOp default values.
1273 mFromMemory = mParams.fromMemory();
1276 nsresult GetOriginUsageOp::DoInit(QuotaManager& aQuotaManager) {
1277 AssertIsOnOwningThread();
1279 QM_TRY_UNWRAP(
1280 mPrincipalMetadata,
1281 aQuotaManager.GetInfoFromValidatedPrincipalInfo(mParams.principalInfo()));
1283 mPrincipalMetadata.AssertInvariants();
1285 return NS_OK;
1288 RefPtr<BoolPromise> GetOriginUsageOp::OpenDirectory() {
1289 AssertIsOnOwningThread();
1291 return OpenStorageDirectory(
1292 Nullable<PersistenceType>(),
1293 OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
1294 Nullable<Client::Type>(),
1295 /* aExclusive */ false);
1298 nsresult GetOriginUsageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1299 AssertIsOnIOThread();
1300 aQuotaManager.AssertStorageIsInitializedInternal();
1301 MOZ_ASSERT(mUsageInfo.TotalUsage().isNothing());
1303 AUTO_PROFILER_LABEL("GetOriginUsageOp::DoDirectoryWork", OTHER);
1305 if (mFromMemory) {
1306 // Ensure temporary storage is initialized. If temporary storage hasn't been
1307 // initialized yet, the method will initialize it by traversing the
1308 // repositories for temporary and default storage (including our origin).
1309 QM_TRY(MOZ_TO_RESULT(
1310 aQuotaManager.EnsureTemporaryStorageIsInitializedInternal()));
1312 // Get cached usage (the method doesn't have to stat any files). File usage
1313 // is not tracked in memory separately, so just add to the database usage.
1314 mUsageInfo += DatabaseUsageType(
1315 Some(aQuotaManager.GetOriginUsage(mPrincipalMetadata)));
1317 return NS_OK;
1320 // Add all the persistent/temporary/default storage files we care about.
1321 for (const PersistenceType type : kAllPersistenceTypes) {
1322 const OriginMetadata originMetadata = {mPrincipalMetadata, type};
1324 auto usageInfoOrErr =
1325 GetUsageForOrigin(aQuotaManager, type, originMetadata);
1326 if (NS_WARN_IF(usageInfoOrErr.isErr())) {
1327 return usageInfoOrErr.unwrapErr();
1330 mUsageInfo += usageInfoOrErr.unwrap();
1333 return NS_OK;
1336 void GetOriginUsageOp::GetResponse(UsageRequestResponse& aResponse) {
1337 AssertIsOnOwningThread();
1339 OriginUsageResponse usageResponse;
1341 usageResponse.usageInfo() = mUsageInfo;
1343 aResponse = usageResponse;
1346 void GetOriginUsageOp::CloseDirectory() {
1347 AssertIsOnOwningThread();
1349 mDirectoryLock = nullptr;
1352 StorageNameOp::StorageNameOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
1353 : QuotaRequestBase(std::move(aQuotaManager), "dom::quota::StorageNameOp") {
1354 AssertIsOnOwningThread();
1357 RefPtr<BoolPromise> StorageNameOp::OpenDirectory() {
1358 AssertIsOnOwningThread();
1360 return BoolPromise::CreateAndResolve(true, __func__);
1363 nsresult StorageNameOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1364 AssertIsOnIOThread();
1366 AUTO_PROFILER_LABEL("StorageNameOp::DoDirectoryWork", OTHER);
1368 mName = aQuotaManager.GetStorageName();
1370 return NS_OK;
1373 void StorageNameOp::GetResponse(RequestResponse& aResponse) {
1374 AssertIsOnOwningThread();
1376 StorageNameResponse storageNameResponse;
1378 storageNameResponse.name() = mName;
1380 aResponse = storageNameResponse;
1383 void StorageNameOp::CloseDirectory() { AssertIsOnOwningThread(); }
1385 InitializedRequestBase::InitializedRequestBase(
1386 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName)
1387 : ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
1388 mInitialized(false) {
1389 AssertIsOnOwningThread();
1392 RefPtr<BoolPromise> InitializedRequestBase::OpenDirectory() {
1393 AssertIsOnOwningThread();
1395 return BoolPromise::CreateAndResolve(true, __func__);
1398 void InitializedRequestBase::CloseDirectory() { AssertIsOnOwningThread(); }
1400 nsresult StorageInitializedOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1401 AssertIsOnIOThread();
1403 AUTO_PROFILER_LABEL("StorageInitializedOp::DoDirectoryWork", OTHER);
1405 mInitialized = aQuotaManager.IsStorageInitializedInternal();
1407 return NS_OK;
1410 bool StorageInitializedOp::GetResolveValue() {
1411 AssertIsOnOwningThread();
1413 return mInitialized;
1416 nsresult TemporaryStorageInitializedOp::DoDirectoryWork(
1417 QuotaManager& aQuotaManager) {
1418 AssertIsOnIOThread();
1420 AUTO_PROFILER_LABEL("TemporaryStorageInitializedOp::DoDirectoryWork", OTHER);
1422 mInitialized = aQuotaManager.IsTemporaryStorageInitializedInternal();
1424 return NS_OK;
1427 bool TemporaryStorageInitializedOp::GetResolveValue() {
1428 AssertIsOnOwningThread();
1430 return mInitialized;
1433 InitOp::InitOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1434 RefPtr<UniversalDirectoryLock> aDirectoryLock)
1435 : ResolvableNormalOriginOp(std::move(aQuotaManager), "dom::quota::InitOp"),
1436 mDirectoryLock(std::move(aDirectoryLock)) {
1437 AssertIsOnOwningThread();
1438 MOZ_ASSERT(mDirectoryLock);
1441 RefPtr<BoolPromise> InitOp::OpenDirectory() {
1442 AssertIsOnOwningThread();
1443 MOZ_ASSERT(mDirectoryLock);
1445 return BoolPromise::CreateAndResolve(true, __func__);
1448 nsresult InitOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1449 AssertIsOnIOThread();
1451 AUTO_PROFILER_LABEL("InitOp::DoDirectoryWork", OTHER);
1453 QM_TRY(MOZ_TO_RESULT(aQuotaManager.EnsureStorageIsInitializedInternal()));
1455 return NS_OK;
1458 bool InitOp::GetResolveValue() { return true; }
1460 void InitOp::CloseDirectory() {
1461 AssertIsOnOwningThread();
1463 mDirectoryLock = nullptr;
1466 InitTemporaryStorageOp::InitTemporaryStorageOp(
1467 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1468 RefPtr<UniversalDirectoryLock> aDirectoryLock)
1469 : ResolvableNormalOriginOp(std::move(aQuotaManager),
1470 "dom::quota::InitTemporaryStorageOp"),
1471 mDirectoryLock(std::move(aDirectoryLock)) {
1472 AssertIsOnOwningThread();
1475 RefPtr<BoolPromise> InitTemporaryStorageOp::OpenDirectory() {
1476 AssertIsOnOwningThread();
1477 MOZ_ASSERT(mDirectoryLock);
1479 return BoolPromise::CreateAndResolve(true, __func__);
1482 nsresult InitTemporaryStorageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1483 AssertIsOnIOThread();
1485 AUTO_PROFILER_LABEL("InitTemporaryStorageOp::DoDirectoryWork", OTHER);
1487 QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
1488 NS_ERROR_NOT_INITIALIZED);
1490 QM_TRY(MOZ_TO_RESULT(
1491 aQuotaManager.EnsureTemporaryStorageIsInitializedInternal()));
1493 return NS_OK;
1496 bool InitTemporaryStorageOp::GetResolveValue() {
1497 AssertIsOnOwningThread();
1499 return true;
1502 void InitTemporaryStorageOp::CloseDirectory() {
1503 AssertIsOnOwningThread();
1505 mDirectoryLock = nullptr;
1508 InitializeOriginRequestBase::InitializeOriginRequestBase(
1509 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
1510 const PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo)
1511 : QuotaRequestBase(std::move(aQuotaManager), aName),
1512 mPrincipalInfo(aPrincipalInfo),
1513 mPersistenceType(aPersistenceType),
1514 mCreated(false) {
1515 AssertIsOnOwningThread();
1518 nsresult InitializeOriginRequestBase::DoInit(QuotaManager& aQuotaManager) {
1519 AssertIsOnOwningThread();
1521 QM_TRY_UNWRAP(
1522 mPrincipalMetadata,
1523 aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
1525 mPrincipalMetadata.AssertInvariants();
1527 return NS_OK;
1530 RefPtr<BoolPromise> InitializeOriginRequestBase::OpenDirectory() {
1531 AssertIsOnOwningThread();
1533 mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
1534 Nullable<PersistenceType>(mPersistenceType),
1535 OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
1536 Nullable<Client::Type>(), /* aExclusive */ false);
1538 return mDirectoryLock->Acquire();
1541 void InitializeOriginRequestBase::CloseDirectory() {
1542 AssertIsOnOwningThread();
1544 mDirectoryLock = nullptr;
1547 InitializePersistentOriginOp::InitializePersistentOriginOp(
1548 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1549 const RequestParams& aParams)
1550 : InitializeOriginRequestBase(
1551 std::move(aQuotaManager), "dom::quota::InitializePersistentOriginOp",
1552 PERSISTENCE_TYPE_PERSISTENT,
1553 aParams.get_InitializePersistentOriginParams().principalInfo()) {
1554 AssertIsOnOwningThread();
1555 MOZ_ASSERT(aParams.type() ==
1556 RequestParams::TInitializePersistentOriginParams);
1559 nsresult InitializePersistentOriginOp::DoDirectoryWork(
1560 QuotaManager& aQuotaManager) {
1561 AssertIsOnIOThread();
1563 AUTO_PROFILER_LABEL("InitializePersistentOriginOp::DoDirectoryWork", OTHER);
1565 QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
1566 NS_ERROR_NOT_INITIALIZED);
1568 QM_TRY_UNWRAP(mCreated,
1569 (aQuotaManager
1570 .EnsurePersistentOriginIsInitialized(OriginMetadata{
1571 mPrincipalMetadata, PERSISTENCE_TYPE_PERSISTENT})
1572 .map([](const auto& res) { return res.second; })));
1574 return NS_OK;
1577 void InitializePersistentOriginOp::GetResponse(RequestResponse& aResponse) {
1578 AssertIsOnOwningThread();
1580 aResponse = InitializePersistentOriginResponse(mCreated);
1583 InitializeTemporaryOriginOp::InitializeTemporaryOriginOp(
1584 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1585 const RequestParams& aParams)
1586 : InitializeOriginRequestBase(
1587 std::move(aQuotaManager), "dom::quota::InitializeTemporaryOriginOp",
1588 aParams.get_InitializeTemporaryOriginParams().persistenceType(),
1589 aParams.get_InitializeTemporaryOriginParams().principalInfo()) {
1590 AssertIsOnOwningThread();
1591 MOZ_ASSERT(aParams.type() == RequestParams::TInitializeTemporaryOriginParams);
1594 nsresult InitializeTemporaryOriginOp::DoDirectoryWork(
1595 QuotaManager& aQuotaManager) {
1596 AssertIsOnIOThread();
1598 AUTO_PROFILER_LABEL("InitializeTemporaryOriginOp::DoDirectoryWork", OTHER);
1600 QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
1601 NS_ERROR_NOT_INITIALIZED);
1603 QM_TRY(OkIf(aQuotaManager.IsTemporaryStorageInitializedInternal()),
1604 NS_ERROR_NOT_INITIALIZED);
1606 QM_TRY_UNWRAP(mCreated,
1607 (aQuotaManager
1608 .EnsureTemporaryOriginIsInitialized(
1609 mPersistenceType,
1610 OriginMetadata{mPrincipalMetadata, mPersistenceType})
1611 .map([](const auto& res) { return res.second; })));
1613 return NS_OK;
1616 void InitializeTemporaryOriginOp::GetResponse(RequestResponse& aResponse) {
1617 AssertIsOnOwningThread();
1619 aResponse = InitializeTemporaryOriginResponse(mCreated);
1622 InitializeClientBase::InitializeClientBase(
1623 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
1624 const PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
1625 Client::Type aClientType)
1626 : ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
1627 mPrincipalInfo(aPrincipalInfo),
1628 mPersistenceType(aPersistenceType),
1629 mClientType(aClientType),
1630 mCreated(false) {
1631 AssertIsOnOwningThread();
1634 nsresult InitializeClientBase::DoInit(QuotaManager& aQuotaManager) {
1635 AssertIsOnOwningThread();
1637 QM_TRY_UNWRAP(
1638 PrincipalMetadata principalMetadata,
1639 aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
1641 principalMetadata.AssertInvariants();
1643 mClientMetadata = {
1644 OriginMetadata{std::move(principalMetadata), mPersistenceType},
1645 mClientType};
1647 return NS_OK;
1650 RefPtr<BoolPromise> InitializeClientBase::OpenDirectory() {
1651 AssertIsOnOwningThread();
1653 mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
1654 Nullable(mPersistenceType),
1655 OriginScope::FromOrigin(mClientMetadata.mOrigin),
1656 Nullable(mClientMetadata.mClientType), /* aExclusive */ false);
1658 return mDirectoryLock->Acquire();
1661 void InitializeClientBase::CloseDirectory() {
1662 AssertIsOnOwningThread();
1664 mDirectoryLock = nullptr;
1667 InitializePersistentClientOp::InitializePersistentClientOp(
1668 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1669 const PrincipalInfo& aPrincipalInfo, Client::Type aClientType)
1670 : InitializeClientBase(
1671 std::move(aQuotaManager), "dom::quota::InitializePersistentClientOp",
1672 PERSISTENCE_TYPE_PERSISTENT, aPrincipalInfo, aClientType) {
1673 AssertIsOnOwningThread();
1676 nsresult InitializePersistentClientOp::DoDirectoryWork(
1677 QuotaManager& aQuotaManager) {
1678 AssertIsOnIOThread();
1680 AUTO_PROFILER_LABEL("InitializePersistentClientOp::DoDirectoryWork", OTHER);
1682 QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsStorageInitializedInternal()),
1683 NS_ERROR_FAILURE);
1685 QM_TRY(
1686 MOZ_TO_RESULT(aQuotaManager.IsOriginInitialized(mClientMetadata.mOrigin)),
1687 NS_ERROR_FAILURE);
1689 QM_TRY_UNWRAP(
1690 mCreated,
1691 (aQuotaManager.EnsurePersistentClientIsInitialized(mClientMetadata)
1692 .map([](const auto& res) { return res.second; })));
1694 return NS_OK;
1697 bool InitializePersistentClientOp::GetResolveValue() {
1698 AssertIsOnOwningThread();
1700 return mCreated;
1703 InitializeTemporaryClientOp::InitializeTemporaryClientOp(
1704 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1705 PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
1706 Client::Type aClientType)
1707 : InitializeClientBase(std::move(aQuotaManager),
1708 "dom::quota::InitializeTemporaryClientOp",
1709 aPersistenceType, aPrincipalInfo, aClientType) {
1710 AssertIsOnOwningThread();
1713 nsresult InitializeTemporaryClientOp::DoDirectoryWork(
1714 QuotaManager& aQuotaManager) {
1715 AssertIsOnIOThread();
1717 AUTO_PROFILER_LABEL("InitializeTemporaryClientOp::DoDirectoryWork", OTHER);
1719 QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsStorageInitializedInternal()),
1720 NS_ERROR_FAILURE);
1722 QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsTemporaryStorageInitializedInternal()),
1723 NS_ERROR_FAILURE);
1725 QM_TRY(MOZ_TO_RESULT(
1726 aQuotaManager.IsTemporaryOriginInitialized(mClientMetadata)),
1727 NS_ERROR_FAILURE);
1729 QM_TRY_UNWRAP(
1730 mCreated,
1731 (aQuotaManager.EnsureTemporaryClientIsInitialized(mClientMetadata)
1732 .map([](const auto& res) { return res.second; })));
1734 return NS_OK;
1737 bool InitializeTemporaryClientOp::GetResolveValue() {
1738 AssertIsOnOwningThread();
1740 return mCreated;
1743 GetFullOriginMetadataOp::GetFullOriginMetadataOp(
1744 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
1745 const GetFullOriginMetadataParams& aParams)
1746 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
1747 "dom::quota::GetFullOriginMetadataOp"),
1748 mParams(aParams) {
1749 AssertIsOnOwningThread();
1752 nsresult GetFullOriginMetadataOp::DoInit(QuotaManager& aQuotaManager) {
1753 AssertIsOnOwningThread();
1755 QM_TRY_UNWRAP(
1756 PrincipalMetadata principalMetadata,
1757 aQuotaManager.GetInfoFromValidatedPrincipalInfo(mParams.principalInfo()));
1759 principalMetadata.AssertInvariants();
1761 mOriginMetadata = {std::move(principalMetadata), mParams.persistenceType()};
1763 return NS_OK;
1766 RefPtr<BoolPromise> GetFullOriginMetadataOp::OpenDirectory() {
1767 AssertIsOnOwningThread();
1769 return OpenStorageDirectory(
1770 Nullable<PersistenceType>(mOriginMetadata.mPersistenceType),
1771 OriginScope::FromOrigin(mOriginMetadata.mOrigin),
1772 Nullable<Client::Type>(),
1773 /* aExclusive */ false);
1776 nsresult GetFullOriginMetadataOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1777 AssertIsOnIOThread();
1778 aQuotaManager.AssertStorageIsInitializedInternal();
1780 AUTO_PROFILER_LABEL("GetFullOriginMetadataOp::DoDirectoryWork", OTHER);
1782 // Ensure temporary storage is initialized. If temporary storage hasn't
1783 // been initialized yet, the method will initialize it by traversing the
1784 // repositories for temporary and default storage (including our origin).
1785 QM_TRY(MOZ_TO_RESULT(
1786 aQuotaManager.EnsureTemporaryStorageIsInitializedInternal()));
1788 // Get metadata cached in memory (the method doesn't have to stat any
1789 // files).
1790 mMaybeFullOriginMetadata =
1791 aQuotaManager.GetFullOriginMetadata(mOriginMetadata);
1793 return NS_OK;
1796 void GetFullOriginMetadataOp::GetResponse(RequestResponse& aResponse) {
1797 AssertIsOnOwningThread();
1799 aResponse = GetFullOriginMetadataResponse();
1800 aResponse.get_GetFullOriginMetadataResponse().maybeFullOriginMetadata() =
1801 std::move(mMaybeFullOriginMetadata);
1804 void GetFullOriginMetadataOp::CloseDirectory() {
1805 AssertIsOnOwningThread();
1807 mDirectoryLock = nullptr;
1810 ClearStorageOp::ClearStorageOp(
1811 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
1812 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
1813 "dom::quota::ClearStorageOp") {
1814 AssertIsOnOwningThread();
1817 void ClearStorageOp::DeleteFiles(QuotaManager& aQuotaManager) {
1818 AssertIsOnIOThread();
1820 nsresult rv = aQuotaManager.AboutToClearOrigins(Nullable<PersistenceType>(),
1821 OriginScope::FromNull(),
1822 Nullable<Client::Type>());
1823 if (NS_WARN_IF(NS_FAILED(rv))) {
1824 return;
1827 auto directoryOrErr = QM_NewLocalFile(aQuotaManager.GetStoragePath());
1828 if (NS_WARN_IF(directoryOrErr.isErr())) {
1829 return;
1832 nsCOMPtr<nsIFile> directory = directoryOrErr.unwrap();
1834 rv = directory->Remove(true);
1835 if (rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
1836 // This should never fail if we've closed all storage connections
1837 // correctly...
1838 MOZ_ASSERT(false, "Failed to remove storage directory!");
1842 void ClearStorageOp::DeleteStorageFile(QuotaManager& aQuotaManager) {
1843 AssertIsOnIOThread();
1845 QM_TRY_INSPECT(const auto& storageFile,
1846 QM_NewLocalFile(aQuotaManager.GetBasePath()), QM_VOID);
1848 QM_TRY(MOZ_TO_RESULT(storageFile->Append(aQuotaManager.GetStorageName() +
1849 kSQLiteSuffix)),
1850 QM_VOID);
1852 const nsresult rv = storageFile->Remove(true);
1853 if (rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
1854 // This should never fail if we've closed the storage connection
1855 // correctly...
1856 MOZ_ASSERT(false, "Failed to remove storage file!");
1860 RefPtr<BoolPromise> ClearStorageOp::OpenDirectory() {
1861 AssertIsOnOwningThread();
1863 // Clear directory lock tables (which also saves origin access time) before
1864 // acquiring the exclusive lock below. Otherwise, saving of origin access
1865 // time would be scheduled after storage clearing and that would initialize
1866 // storage again in the end.
1867 mQuotaManager->ClearDirectoryLockTables();
1869 return OpenStorageDirectory(Nullable<PersistenceType>(),
1870 OriginScope::FromNull(), Nullable<Client::Type>(),
1871 /* aExclusive */ true);
1874 nsresult ClearStorageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
1875 AssertIsOnIOThread();
1876 aQuotaManager.AssertStorageIsInitializedInternal();
1878 AUTO_PROFILER_LABEL("ClearStorageOp::DoDirectoryWork", OTHER);
1880 DeleteFiles(aQuotaManager);
1882 aQuotaManager.RemoveQuota();
1884 aQuotaManager.ShutdownStorageInternal();
1886 DeleteStorageFile(aQuotaManager);
1888 return NS_OK;
1891 bool ClearStorageOp::GetResolveValue() {
1892 AssertIsOnOwningThread();
1894 return true;
1897 void ClearStorageOp::CloseDirectory() {
1898 AssertIsOnOwningThread();
1900 mDirectoryLock = nullptr;
1903 void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
1904 const OriginMetadata& aOriginMetadata,
1905 const Nullable<Client::Type>& aClientType) {
1906 AssertIsOnIOThread();
1908 DeleteFilesInternal(
1909 aQuotaManager, aOriginMetadata.mPersistenceType,
1910 OriginScope::FromOrigin(aOriginMetadata.mOrigin), aClientType,
1911 [&aQuotaManager, &aOriginMetadata](
1912 const std::function<Result<Ok, nsresult>(nsCOMPtr<nsIFile>&&)>& aBody)
1913 -> Result<Ok, nsresult> {
1914 QM_TRY_UNWRAP(auto directory,
1915 aQuotaManager.GetOriginDirectory(aOriginMetadata));
1917 QM_TRY_INSPECT(const bool& exists,
1918 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
1920 if (!exists) {
1921 return Ok{};
1924 QM_TRY_RETURN(aBody(std::move(directory)));
1928 void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
1929 PersistenceType aPersistenceType,
1930 const OriginScope& aOriginScope,
1931 const Nullable<Client::Type>& aClientType) {
1932 AssertIsOnIOThread();
1934 DeleteFilesInternal(
1935 aQuotaManager, aPersistenceType, aOriginScope, aClientType,
1936 [&aQuotaManager, &aPersistenceType](
1937 const std::function<Result<Ok, nsresult>(nsCOMPtr<nsIFile>&&)>& aBody)
1938 -> Result<Ok, nsresult> {
1939 QM_TRY_INSPECT(
1940 const auto& directory,
1941 QM_NewLocalFile(aQuotaManager.GetStoragePath(aPersistenceType)));
1943 QM_TRY_INSPECT(const bool& exists,
1944 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
1946 if (!exists) {
1947 return Ok{};
1950 QM_TRY_RETURN(CollectEachFile(*directory, aBody));
1954 template <typename FileCollector>
1955 void ClearRequestBase::DeleteFilesInternal(
1956 QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
1957 const OriginScope& aOriginScope, const Nullable<Client::Type>& aClientType,
1958 const FileCollector& aFileCollector) {
1959 AssertIsOnIOThread();
1961 QM_TRY(MOZ_TO_RESULT(aQuotaManager.AboutToClearOrigins(
1962 Nullable<PersistenceType>(aPersistenceType), aOriginScope,
1963 aClientType)),
1964 QM_VOID);
1966 nsTArray<nsCOMPtr<nsIFile>> directoriesForRemovalRetry;
1968 aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
1969 "ClearRequestBase: Starting deleting files"_ns);
1971 QM_TRY(
1972 aFileCollector([&aClientType, &originScope = aOriginScope,
1973 aPersistenceType, &aQuotaManager,
1974 &directoriesForRemovalRetry](nsCOMPtr<nsIFile>&& file)
1975 -> mozilla::Result<Ok, nsresult> {
1976 QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*file));
1978 QM_TRY_INSPECT(
1979 const auto& leafName,
1980 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, file, GetLeafName));
1982 switch (dirEntryKind) {
1983 case nsIFileKind::ExistsAsDirectory: {
1984 QM_TRY_UNWRAP(auto maybeMetadata,
1985 QM_OR_ELSE_WARN_IF(
1986 // Expression
1987 aQuotaManager.GetOriginMetadata(file).map(
1988 [](auto metadata) -> Maybe<OriginMetadata> {
1989 return Some(std::move(metadata));
1991 // Predicate.
1992 IsSpecificError<NS_ERROR_MALFORMED_URI>,
1993 // Fallback.
1994 ErrToDefaultOk<Maybe<OriginMetadata>>));
1996 if (!maybeMetadata) {
1997 // Unknown directories during clearing are allowed. Just
1998 // warn if we find them.
1999 UNKNOWN_FILE_WARNING(leafName);
2000 break;
2003 auto metadata = maybeMetadata.extract();
2005 MOZ_ASSERT(metadata.mPersistenceType == aPersistenceType);
2007 // Skip the origin directory if it doesn't match the pattern.
2008 if (!originScope.Matches(
2009 OriginScope::FromOrigin(metadata.mOrigin))) {
2010 break;
2013 if (!aClientType.IsNull()) {
2014 nsAutoString clientDirectoryName;
2015 QM_TRY(OkIf(Client::TypeToText(aClientType.Value(),
2016 clientDirectoryName, fallible)),
2017 Err(NS_ERROR_FAILURE));
2019 QM_TRY(MOZ_TO_RESULT(file->Append(clientDirectoryName)));
2021 QM_TRY_INSPECT(const bool& exists,
2022 MOZ_TO_RESULT_INVOKE_MEMBER(file, Exists));
2024 if (!exists) {
2025 break;
2029 // We can't guarantee that this will always succeed on
2030 // Windows...
2031 QM_WARNONLY_TRY(
2032 aQuotaManager.RemoveOriginDirectory(*file), [&](const auto&) {
2033 directoriesForRemovalRetry.AppendElement(std::move(file));
2036 const bool initialized =
2037 aPersistenceType == PERSISTENCE_TYPE_PERSISTENT
2038 ? aQuotaManager.IsOriginInitialized(metadata.mOrigin)
2039 : aQuotaManager.IsTemporaryStorageInitializedInternal();
2041 // If it hasn't been initialized, we don't need to update the
2042 // quota and notify the removing client.
2043 if (!initialized) {
2044 break;
2047 if (aPersistenceType != PERSISTENCE_TYPE_PERSISTENT) {
2048 if (aClientType.IsNull()) {
2049 aQuotaManager.RemoveQuotaForOrigin(aPersistenceType, metadata);
2050 } else {
2051 aQuotaManager.ResetUsageForClient(
2052 ClientMetadata{metadata, aClientType.Value()});
2056 aQuotaManager.OriginClearCompleted(aPersistenceType,
2057 metadata.mOrigin, aClientType);
2059 break;
2062 case nsIFileKind::ExistsAsFile: {
2063 // Unknown files during clearing are allowed. Just warn if we
2064 // find them.
2065 if (!IsOSMetadata(leafName)) {
2066 UNKNOWN_FILE_WARNING(leafName);
2069 break;
2072 case nsIFileKind::DoesNotExist:
2073 // Ignore files that got removed externally while iterating.
2074 break;
2077 return Ok{};
2079 QM_VOID);
2081 // Retry removing any directories that failed to be removed earlier now.
2083 // XXX This will still block this operation. We might instead dispatch a
2084 // runnable to our own thread for each retry round with a timer. We must
2085 // ensure that the directory lock is upheld until we complete or give up
2086 // though.
2087 for (uint32_t index = 0; index < 10; index++) {
2088 aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
2089 return nsPrintfCString(
2090 "ClearRequestBase: Starting repeated directory removal #%d", index);
2093 for (auto&& file : std::exchange(directoriesForRemovalRetry,
2094 nsTArray<nsCOMPtr<nsIFile>>{})) {
2095 QM_WARNONLY_TRY(
2096 aQuotaManager.RemoveOriginDirectory(*file),
2097 ([&directoriesForRemovalRetry, &file](const auto&) {
2098 directoriesForRemovalRetry.AppendElement(std::move(file));
2099 }));
2102 aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
2103 return nsPrintfCString(
2104 "ClearRequestBase: Completed repeated directory removal #%d", index);
2107 if (directoriesForRemovalRetry.IsEmpty()) {
2108 break;
2111 aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
2112 return nsPrintfCString("ClearRequestBase: Before sleep #%d", index);
2115 PR_Sleep(PR_MillisecondsToInterval(200));
2117 aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
2118 return nsPrintfCString("ClearRequestBase: After sleep #%d", index);
2122 QM_WARNONLY_TRY(OkIf(directoriesForRemovalRetry.IsEmpty()));
2124 aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
2125 "ClearRequestBase: Completed deleting files"_ns);
2128 ClearOriginOp::ClearOriginOp(
2129 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2130 const mozilla::Maybe<PersistenceType>& aPersistenceType,
2131 const PrincipalInfo& aPrincipalInfo,
2132 const mozilla::Maybe<Client::Type>& aClientType)
2133 : ClearRequestBase(std::move(aQuotaManager), "dom::quota::ClearOriginOp"),
2134 mPrincipalInfo(aPrincipalInfo),
2135 mPersistenceType(aPersistenceType
2136 ? Nullable<PersistenceType>(*aPersistenceType)
2137 : Nullable<PersistenceType>()),
2138 mClientType(aClientType ? Nullable<Client::Type>(*aClientType)
2139 : Nullable<Client::Type>()) {
2140 AssertIsOnOwningThread();
2143 nsresult ClearOriginOp::DoInit(QuotaManager& aQuotaManager) {
2144 AssertIsOnOwningThread();
2146 QM_TRY_UNWRAP(
2147 mPrincipalMetadata,
2148 aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
2150 mPrincipalMetadata.AssertInvariants();
2152 return NS_OK;
2155 RefPtr<BoolPromise> ClearOriginOp::OpenDirectory() {
2156 AssertIsOnOwningThread();
2158 return OpenStorageDirectory(
2159 mPersistenceType, OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
2160 mClientType,
2161 /* aExclusive */ true);
2164 nsresult ClearOriginOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
2165 AssertIsOnIOThread();
2166 aQuotaManager.AssertStorageIsInitializedInternal();
2168 AUTO_PROFILER_LABEL("ClearRequestBase::DoDirectoryWork", OTHER);
2170 if (mPersistenceType.IsNull()) {
2171 for (const PersistenceType type : kAllPersistenceTypes) {
2172 DeleteFiles(aQuotaManager, OriginMetadata(mPrincipalMetadata, type),
2173 mClientType);
2175 } else {
2176 DeleteFiles(aQuotaManager,
2177 OriginMetadata(mPrincipalMetadata, mPersistenceType.Value()),
2178 mClientType);
2181 return NS_OK;
2184 bool ClearOriginOp::GetResolveValue() {
2185 AssertIsOnOwningThread();
2187 return true;
2190 void ClearOriginOp::CloseDirectory() {
2191 AssertIsOnOwningThread();
2193 mDirectoryLock = nullptr;
2196 ClearStoragesForOriginPrefixOp::ClearStoragesForOriginPrefixOp(
2197 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2198 const Maybe<PersistenceType>& aPersistenceType,
2199 const PrincipalInfo& aPrincipalInfo)
2200 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
2201 "dom::quota::ClearStoragesForOriginPrefixOp"),
2202 mPrefix(
2203 QuotaManager::GetOriginFromValidatedPrincipalInfo(aPrincipalInfo)),
2204 mPersistenceType(aPersistenceType
2205 ? Nullable<PersistenceType>(*aPersistenceType)
2206 : Nullable<PersistenceType>()) {
2207 AssertIsOnOwningThread();
2210 RefPtr<BoolPromise> ClearStoragesForOriginPrefixOp::OpenDirectory() {
2211 AssertIsOnOwningThread();
2213 return OpenStorageDirectory(mPersistenceType,
2214 OriginScope::FromPrefix(mPrefix),
2215 Nullable<Client::Type>(),
2216 /* aExclusive */ true);
2219 nsresult ClearStoragesForOriginPrefixOp::DoDirectoryWork(
2220 QuotaManager& aQuotaManager) {
2221 AssertIsOnIOThread();
2223 AUTO_PROFILER_LABEL("ClearStoragesForOriginPrefixOp::DoDirectoryWork", OTHER);
2225 if (mPersistenceType.IsNull()) {
2226 for (const PersistenceType type : kAllPersistenceTypes) {
2227 DeleteFiles(aQuotaManager, type, OriginScope::FromPrefix(mPrefix),
2228 Nullable<Client::Type>());
2230 } else {
2231 DeleteFiles(aQuotaManager, mPersistenceType.Value(),
2232 OriginScope::FromPrefix(mPrefix), Nullable<Client::Type>());
2235 return NS_OK;
2238 bool ClearStoragesForOriginPrefixOp::GetResolveValue() {
2239 AssertIsOnOwningThread();
2241 return true;
2244 void ClearStoragesForOriginPrefixOp::CloseDirectory() {
2245 AssertIsOnOwningThread();
2247 mDirectoryLock = nullptr;
2250 ClearDataOp::ClearDataOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2251 const OriginAttributesPattern& aPattern)
2252 : ClearRequestBase(std::move(aQuotaManager), "dom::quota::ClearDataOp"),
2253 mPattern(aPattern) {}
2255 RefPtr<BoolPromise> ClearDataOp::OpenDirectory() {
2256 AssertIsOnOwningThread();
2258 return OpenStorageDirectory(Nullable<PersistenceType>(),
2259 OriginScope::FromPattern(mPattern),
2260 Nullable<Client::Type>(),
2261 /* aExclusive */ true);
2264 nsresult ClearDataOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
2265 AssertIsOnIOThread();
2267 AUTO_PROFILER_LABEL("ClearRequestBase::DoDirectoryWork", OTHER);
2269 for (const PersistenceType type : kAllPersistenceTypes) {
2270 DeleteFiles(aQuotaManager, type, OriginScope::FromPattern(mPattern),
2271 Nullable<Client::Type>());
2274 return NS_OK;
2277 bool ClearDataOp::GetResolveValue() {
2278 AssertIsOnOwningThread();
2280 return true;
2283 void ClearDataOp::CloseDirectory() {
2284 AssertIsOnOwningThread();
2286 mDirectoryLock = nullptr;
2289 ResetOriginOp::ResetOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2290 const RequestParams& aParams)
2291 : QuotaRequestBase(std::move(aQuotaManager), "dom::quota::ResetOriginOp") {
2292 AssertIsOnOwningThread();
2293 MOZ_ASSERT(aParams.type() == RequestParams::TResetOriginParams);
2295 const ClearResetOriginParams& params =
2296 aParams.get_ResetOriginParams().commonParams();
2298 mOrigin =
2299 QuotaManager::GetOriginFromValidatedPrincipalInfo(params.principalInfo());
2301 if (params.persistenceTypeIsExplicit()) {
2302 mPersistenceType.SetValue(params.persistenceType());
2305 if (params.clientTypeIsExplicit()) {
2306 mClientType.SetValue(params.clientType());
2310 RefPtr<BoolPromise> ResetOriginOp::OpenDirectory() {
2311 AssertIsOnOwningThread();
2313 mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
2314 mPersistenceType, OriginScope::FromOrigin(mOrigin), mClientType,
2315 /* aExclusive */ true);
2317 return mDirectoryLock->Acquire();
2320 nsresult ResetOriginOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
2321 AssertIsOnIOThread();
2323 AUTO_PROFILER_LABEL("ResetOriginOp::DoDirectoryWork", OTHER);
2325 // All the work is handled by NormalOriginOperationBase parent class. In
2326 // this particular case, we just needed to acquire an exclusive directory
2327 // lock and that's it.
2329 return NS_OK;
2332 void ResetOriginOp::GetResponse(RequestResponse& aResponse) {
2333 AssertIsOnOwningThread();
2335 aResponse = ResetOriginResponse();
2338 void ResetOriginOp::CloseDirectory() {
2339 AssertIsOnOwningThread();
2341 mDirectoryLock = nullptr;
2344 PersistRequestBase::PersistRequestBase(
2345 MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2346 const PrincipalInfo& aPrincipalInfo)
2347 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
2348 "dom::quota::PersistRequestBase"),
2349 mPrincipalInfo(aPrincipalInfo) {
2350 AssertIsOnOwningThread();
2353 nsresult PersistRequestBase::DoInit(QuotaManager& aQuotaManager) {
2354 AssertIsOnOwningThread();
2356 // Figure out which origin we're dealing with.
2357 QM_TRY_UNWRAP(
2358 mPrincipalMetadata,
2359 aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
2361 mPrincipalMetadata.AssertInvariants();
2363 return NS_OK;
2366 RefPtr<BoolPromise> PersistRequestBase::OpenDirectory() {
2367 AssertIsOnOwningThread();
2369 return OpenStorageDirectory(
2370 Nullable<PersistenceType>(PERSISTENCE_TYPE_DEFAULT),
2371 OriginScope::FromOrigin(mPrincipalMetadata.mOrigin),
2372 Nullable<Client::Type>(),
2373 /* aExclusive */ false);
2376 void PersistRequestBase::CloseDirectory() {
2377 AssertIsOnOwningThread();
2379 mDirectoryLock = nullptr;
2382 PersistedOp::PersistedOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2383 const RequestParams& aParams)
2384 : PersistRequestBase(std::move(aQuotaManager),
2385 aParams.get_PersistedParams().principalInfo()),
2386 mPersisted(false) {
2387 MOZ_ASSERT(aParams.type() == RequestParams::TPersistedParams);
2390 nsresult PersistedOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
2391 AssertIsOnIOThread();
2392 aQuotaManager.AssertStorageIsInitializedInternal();
2394 AUTO_PROFILER_LABEL("PersistedOp::DoDirectoryWork", OTHER);
2396 const OriginMetadata originMetadata = {mPrincipalMetadata,
2397 PERSISTENCE_TYPE_DEFAULT};
2399 Nullable<bool> persisted = aQuotaManager.OriginPersisted(originMetadata);
2401 if (!persisted.IsNull()) {
2402 mPersisted = persisted.Value();
2403 return NS_OK;
2406 // If we get here, it means the origin hasn't been initialized yet.
2407 // Try to get the persisted flag from directory metadata on disk.
2409 QM_TRY_INSPECT(const auto& directory,
2410 aQuotaManager.GetOriginDirectory(originMetadata));
2412 QM_TRY_INSPECT(const bool& exists,
2413 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
2415 if (exists) {
2416 // Get the metadata. We only use the persisted flag.
2417 QM_TRY_INSPECT(const auto& metadata,
2418 aQuotaManager.LoadFullOriginMetadataWithRestore(directory));
2420 mPersisted = metadata.mPersisted;
2421 } else {
2422 // The directory has not been created yet.
2423 mPersisted = false;
2426 return NS_OK;
2429 void PersistedOp::GetResponse(RequestResponse& aResponse) {
2430 AssertIsOnOwningThread();
2432 PersistedResponse persistedResponse;
2433 persistedResponse.persisted() = mPersisted;
2435 aResponse = persistedResponse;
2438 PersistOp::PersistOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2439 const RequestParams& aParams)
2440 : PersistRequestBase(std::move(aQuotaManager),
2441 aParams.get_PersistParams().principalInfo()) {
2442 MOZ_ASSERT(aParams.type() == RequestParams::TPersistParams);
2445 nsresult PersistOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
2446 AssertIsOnIOThread();
2447 aQuotaManager.AssertStorageIsInitializedInternal();
2449 const OriginMetadata originMetadata = {mPrincipalMetadata,
2450 PERSISTENCE_TYPE_DEFAULT};
2452 AUTO_PROFILER_LABEL("PersistOp::DoDirectoryWork", OTHER);
2454 // Update directory metadata on disk first. Then, create/update the
2455 // originInfo if needed.
2456 QM_TRY_INSPECT(const auto& directory,
2457 aQuotaManager.GetOriginDirectory(originMetadata));
2459 QM_TRY_INSPECT(const bool& created,
2460 aQuotaManager.EnsureOriginDirectory(*directory));
2462 if (created) {
2463 int64_t timestamp;
2465 // Origin directory has been successfully created.
2466 // Create OriginInfo too if temporary storage was already initialized.
2467 if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
2468 timestamp = aQuotaManager.NoteOriginDirectoryCreated(
2469 originMetadata, /* aPersisted */ true);
2470 } else {
2471 timestamp = PR_Now();
2474 QM_TRY(MOZ_TO_RESULT(QuotaManager::CreateDirectoryMetadata2(
2475 *directory, timestamp,
2476 /* aPersisted */ true, originMetadata)));
2477 } else {
2478 // Get the metadata (restore the metadata file if necessary). We only use
2479 // the persisted flag.
2480 QM_TRY_INSPECT(const auto& metadata,
2481 aQuotaManager.LoadFullOriginMetadataWithRestore(directory));
2483 if (!metadata.mPersisted) {
2484 QM_TRY_INSPECT(const auto& file,
2485 CloneFileAndAppend(
2486 *directory, nsLiteralString(METADATA_V2_FILE_NAME)));
2488 QM_TRY_INSPECT(const auto& stream,
2489 GetBinaryOutputStream(*file, FileFlag::Update));
2491 MOZ_ASSERT(stream);
2493 // Update origin access time while we are here.
2494 QM_TRY(MOZ_TO_RESULT(stream->Write64(PR_Now())));
2496 // Set the persisted flag to true.
2497 QM_TRY(MOZ_TO_RESULT(stream->WriteBoolean(true)));
2500 // Directory metadata has been successfully updated.
2501 // Update OriginInfo too if temporary storage was already initialized.
2502 if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
2503 aQuotaManager.PersistOrigin(originMetadata);
2507 return NS_OK;
2510 void PersistOp::GetResponse(RequestResponse& aResponse) {
2511 AssertIsOnOwningThread();
2513 aResponse = PersistResponse();
2516 EstimateOp::EstimateOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
2517 const EstimateParams& aParams)
2518 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
2519 "dom::quota::EstimateOp"),
2520 mParams(aParams) {
2521 AssertIsOnOwningThread();
2524 nsresult EstimateOp::DoInit(QuotaManager& aQuotaManager) {
2525 AssertIsOnOwningThread();
2527 QM_TRY_UNWRAP(
2528 PrincipalMetadata principalMetadata,
2529 aQuotaManager.GetInfoFromValidatedPrincipalInfo(mParams.principalInfo()));
2531 principalMetadata.AssertInvariants();
2533 mOriginMetadata = {std::move(principalMetadata), PERSISTENCE_TYPE_DEFAULT};
2535 return NS_OK;
2538 RefPtr<BoolPromise> EstimateOp::OpenDirectory() {
2539 AssertIsOnOwningThread();
2541 // XXX In theory, we should be locking entire group, not just one origin.
2542 return OpenStorageDirectory(
2543 Nullable<PersistenceType>(mOriginMetadata.mPersistenceType),
2544 OriginScope::FromOrigin(mOriginMetadata.mOrigin),
2545 Nullable<Client::Type>(),
2546 /* aExclusive */ false);
2549 nsresult EstimateOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
2550 AssertIsOnIOThread();
2551 aQuotaManager.AssertStorageIsInitializedInternal();
2553 AUTO_PROFILER_LABEL("EstimateOp::DoDirectoryWork", OTHER);
2555 // Ensure temporary storage is initialized. If temporary storage hasn't been
2556 // initialized yet, the method will initialize it by traversing the
2557 // repositories for temporary and default storage (including origins
2558 // belonging to our group).
2559 QM_TRY(MOZ_TO_RESULT(
2560 aQuotaManager.EnsureTemporaryStorageIsInitializedInternal()));
2562 // Get cached usage (the method doesn't have to stat any files).
2563 mUsageAndLimit = aQuotaManager.GetUsageAndLimitForEstimate(mOriginMetadata);
2565 return NS_OK;
2568 void EstimateOp::GetResponse(RequestResponse& aResponse) {
2569 AssertIsOnOwningThread();
2571 EstimateResponse estimateResponse;
2573 estimateResponse.usage() = mUsageAndLimit.first;
2574 estimateResponse.limit() = mUsageAndLimit.second;
2576 aResponse = estimateResponse;
2579 void EstimateOp::CloseDirectory() {
2580 AssertIsOnOwningThread();
2582 mDirectoryLock = nullptr;
2585 ListOriginsOp::ListOriginsOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
2586 : OpenStorageDirectoryHelper(std::move(aQuotaManager),
2587 "dom::quota::ListOriginsOp") {
2588 AssertIsOnOwningThread();
2591 RefPtr<BoolPromise> ListOriginsOp::OpenDirectory() {
2592 AssertIsOnOwningThread();
2594 return OpenStorageDirectory(Nullable<PersistenceType>(),
2595 OriginScope::FromNull(), Nullable<Client::Type>(),
2596 /* aExclusive */ false);
2599 nsresult ListOriginsOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
2600 AssertIsOnIOThread();
2601 aQuotaManager.AssertStorageIsInitializedInternal();
2603 AUTO_PROFILER_LABEL("ListOriginsOp::DoDirectoryWork", OTHER);
2605 for (const PersistenceType type : kAllPersistenceTypes) {
2606 QM_TRY(MOZ_TO_RESULT(TraverseRepository(aQuotaManager, type)));
2609 // TraverseRepository above only consulted the file-system to get a list of
2610 // known origins, but we also need to include origins that have pending
2611 // quota usage.
2613 aQuotaManager.CollectPendingOriginsForListing([this](const auto& originInfo) {
2614 mOrigins.AppendElement(originInfo->Origin());
2617 return NS_OK;
2620 const Atomic<bool>& ListOriginsOp::GetIsCanceledFlag() {
2621 AssertIsOnIOThread();
2623 return mCanceled;
2626 nsresult ListOriginsOp::ProcessOrigin(QuotaManager& aQuotaManager,
2627 nsIFile& aOriginDir,
2628 const bool aPersistent,
2629 const PersistenceType aPersistenceType) {
2630 AssertIsOnIOThread();
2632 QM_TRY_UNWRAP(auto maybeMetadata,
2633 QM_OR_ELSE_WARN_IF(
2634 // Expression
2635 aQuotaManager.GetOriginMetadata(&aOriginDir)
2636 .map([](auto metadata) -> Maybe<OriginMetadata> {
2637 return Some(std::move(metadata));
2639 // Predicate.
2640 IsSpecificError<NS_ERROR_MALFORMED_URI>,
2641 // Fallback.
2642 ErrToDefaultOk<Maybe<OriginMetadata>>));
2644 if (!maybeMetadata) {
2645 // Unknown directories during listing are allowed. Just warn if we find
2646 // them.
2647 QM_TRY_INSPECT(const auto& leafName,
2648 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, aOriginDir,
2649 GetLeafName));
2651 UNKNOWN_FILE_WARNING(leafName);
2652 return NS_OK;
2655 auto metadata = maybeMetadata.extract();
2657 if (aQuotaManager.IsOriginInternal(metadata.mOrigin)) {
2658 return NS_OK;
2661 mOrigins.AppendElement(std::move(metadata.mOrigin));
2663 return NS_OK;
2666 void ListOriginsOp::GetResponse(RequestResponse& aResponse) {
2667 AssertIsOnOwningThread();
2669 aResponse = ListOriginsResponse();
2670 if (mOrigins.IsEmpty()) {
2671 return;
2674 nsTArray<nsCString>& origins = aResponse.get_ListOriginsResponse().origins();
2675 mOrigins.SwapElements(origins);
2678 void ListOriginsOp::CloseDirectory() {
2679 AssertIsOnOwningThread();
2681 mDirectoryLock = nullptr;
2684 } // namespace mozilla::dom::quota