tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

OriginOperations.cpp (125740B)


      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/. */
      6 
      7 #include "OriginOperations.h"
      8 
      9 #include <algorithm>
     10 #include <cstdint>
     11 #include <utility>
     12 
     13 #include "DirectoryMetadata.h"
     14 #include "ErrorList.h"
     15 #include "FileUtils.h"
     16 #include "GroupInfo.h"
     17 #include "MainThreadUtils.h"
     18 #include "NormalOriginOperationBase.h"
     19 #include "OriginInfo.h"
     20 #include "OriginOperationBase.h"
     21 #include "OriginParser.h"
     22 #include "QuotaRequestBase.h"
     23 #include "ResolvableNormalOriginOp.h"
     24 #include "mozilla/Assertions.h"
     25 #include "mozilla/Atomics.h"
     26 #include "mozilla/Maybe.h"
     27 #include "mozilla/NotNull.h"
     28 #include "mozilla/ProfilerLabels.h"
     29 #include "mozilla/RefPtr.h"
     30 #include "mozilla/Result.h"
     31 #include "mozilla/ResultExtensions.h"
     32 #include "mozilla/StaticPrefs_dom.h"
     33 #include "mozilla/dom/Nullable.h"
     34 #include "mozilla/dom/quota/Client.h"
     35 #include "mozilla/dom/quota/CommonMetadata.h"
     36 #include "mozilla/dom/quota/Constants.h"
     37 #include "mozilla/dom/quota/Date.h"
     38 #include "mozilla/dom/quota/DirectoryLock.h"
     39 #include "mozilla/dom/quota/DirectoryLockInlines.h"
     40 #include "mozilla/dom/quota/OriginDirectoryLock.h"
     41 #include "mozilla/dom/quota/OriginScope.h"
     42 #include "mozilla/dom/quota/PQuota.h"
     43 #include "mozilla/dom/quota/PQuotaRequest.h"
     44 #include "mozilla/dom/quota/PQuotaUsageRequest.h"
     45 #include "mozilla/dom/quota/PersistenceScope.h"
     46 #include "mozilla/dom/quota/PersistenceType.h"
     47 #include "mozilla/dom/quota/PrincipalUtils.h"
     48 #include "mozilla/dom/quota/QuotaCommon.h"
     49 #include "mozilla/dom/quota/QuotaManager.h"
     50 #include "mozilla/dom/quota/QuotaManagerImpl.h"
     51 #include "mozilla/dom/quota/ResultExtensions.h"
     52 #include "mozilla/dom/quota/StreamUtils.h"
     53 #include "mozilla/dom/quota/UniversalDirectoryLock.h"
     54 #include "mozilla/dom/quota/UsageInfo.h"
     55 #include "mozilla/fallible.h"
     56 #include "mozilla/ipc/BackgroundParent.h"
     57 #include "mozilla/ipc/PBackgroundSharedTypes.h"
     58 #include "nsCOMPtr.h"
     59 #include "nsDebug.h"
     60 #include "nsError.h"
     61 #include "nsHashKeys.h"
     62 #include "nsIBinaryOutputStream.h"
     63 #include "nsIFile.h"
     64 #include "nsIObjectOutputStream.h"
     65 #include "nsIOutputStream.h"
     66 #include "nsLiteralString.h"
     67 #include "nsPrintfCString.h"
     68 #include "nsString.h"
     69 #include "nsTArray.h"
     70 #include "nsTHashMap.h"
     71 #include "prthread.h"
     72 #include "prtime.h"
     73 
     74 namespace mozilla::dom::quota {
     75 
     76 using namespace mozilla::ipc;
     77 
     78 template <class Base>
     79 class OpenStorageDirectoryHelper : public Base {
     80 protected:
     81  OpenStorageDirectoryHelper(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
     82                             const char* aName)
     83      : Base(std::move(aQuotaManager), aName) {}
     84 
     85  RefPtr<BoolPromise> OpenStorageDirectory(
     86      const PersistenceScope& aPersistenceScope,
     87      const OriginScope& aOriginScope,
     88      const ClientStorageScope& aClientStorageScope, bool aExclusive,
     89      bool aInitializeOrigins = false,
     90      DirectoryLockCategory aCategory = DirectoryLockCategory::None);
     91 
     92  RefPtr<UniversalDirectoryLock> mDirectoryLock;
     93 };
     94 
     95 class FinalizeOriginEvictionOp : public OriginOperationBase {
     96  nsTArray<RefPtr<OriginDirectoryLock>> mLocks;
     97 
     98 public:
     99  FinalizeOriginEvictionOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    100                           nsTArray<RefPtr<OriginDirectoryLock>>&& aLocks)
    101      : OriginOperationBase(std::move(aQuotaManager),
    102                            "dom::quota::FinalizeOriginEvictionOp"),
    103        mLocks(std::move(aLocks)) {
    104    AssertIsOnOwningThread();
    105  }
    106 
    107  NS_INLINE_DECL_REFCOUNTING(FinalizeOriginEvictionOp, override)
    108 
    109 private:
    110  ~FinalizeOriginEvictionOp() = default;
    111 
    112  virtual RefPtr<BoolPromise> Open() override;
    113 
    114  virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    115 
    116  virtual void UnblockOpen() override;
    117 };
    118 
    119 class SaveOriginAccessTimeOp : public ResolvableNormalOriginOp<bool> {
    120  const OriginMetadata mOriginMetadata;
    121  RefPtr<UniversalDirectoryLock> mDirectoryLock;
    122  bool mSaved;
    123 
    124 public:
    125  SaveOriginAccessTimeOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    126                         const OriginMetadata& aOriginMetadata,
    127                         RefPtr<UniversalDirectoryLock> aDirectoryLock)
    128      : ResolvableNormalOriginOp(std::move(aQuotaManager),
    129                                 "dom::quota::SaveOriginAccessTimeOp"),
    130        mOriginMetadata(aOriginMetadata),
    131        mDirectoryLock(std::move(aDirectoryLock)),
    132        mSaved(false) {
    133    AssertIsOnOwningThread();
    134  }
    135 
    136 private:
    137  ~SaveOriginAccessTimeOp() = default;
    138 
    139  RefPtr<BoolPromise> OpenDirectory() override;
    140 
    141  virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    142 
    143  bool UnwrapResolveValue() override;
    144 
    145  void CloseDirectory() override;
    146 };
    147 
    148 class ClearPrivateRepositoryOp
    149    : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<bool>> {
    150 public:
    151  explicit ClearPrivateRepositoryOp(
    152      MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
    153      : OpenStorageDirectoryHelper(std::move(aQuotaManager),
    154                                   "dom::quota::ClearPrivateRepositoryOp") {
    155    AssertIsOnOwningThread();
    156  }
    157 
    158 private:
    159  ~ClearPrivateRepositoryOp() = default;
    160 
    161  RefPtr<BoolPromise> OpenDirectory() override;
    162 
    163  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    164 
    165  bool UnwrapResolveValue() override { return true; }
    166 
    167  void CloseDirectory() override;
    168 };
    169 
    170 class ShutdownStorageOp : public ResolvableNormalOriginOp<bool> {
    171  RefPtr<UniversalDirectoryLock> mDirectoryLock;
    172 
    173 public:
    174  explicit ShutdownStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
    175      : ResolvableNormalOriginOp(std::move(aQuotaManager),
    176                                 "dom::quota::ShutdownStorageOp") {
    177    AssertIsOnOwningThread();
    178  }
    179 
    180 private:
    181  ~ShutdownStorageOp() = default;
    182 
    183 #ifdef DEBUG
    184  nsresult DirectoryOpen() override;
    185 #endif
    186 
    187  RefPtr<BoolPromise> OpenDirectory() override;
    188 
    189  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    190 
    191  bool UnwrapResolveValue() override { return true; }
    192 
    193  void CloseDirectory() override;
    194 };
    195 
    196 class CancelableHelper {
    197 protected:
    198  virtual const Atomic<bool>& GetIsCanceledFlag() = 0;
    199 };
    200 
    201 // A mix-in class to simplify operations that need to process every origin in
    202 // one or more repositories. Sub-classes should call TraverseRepository in their
    203 // DoDirectoryWork and implement a ProcessOrigin method for their per-origin
    204 // logic.
    205 class TraverseRepositoryHelper : public CancelableHelper {
    206 public:
    207  TraverseRepositoryHelper() = default;
    208 
    209 protected:
    210  virtual ~TraverseRepositoryHelper() = default;
    211 
    212  // If ProcessOrigin returns an error, TraverseRepository will immediately
    213  // terminate and return the received error code to its caller.
    214  nsresult TraverseRepository(QuotaManager& aQuotaManager,
    215                              PersistenceType aPersistenceType);
    216 
    217 private:
    218  virtual nsresult ProcessOrigin(QuotaManager& aQuotaManager,
    219                                 nsIFile& aOriginDir, const bool aPersistent,
    220                                 const PersistenceType aPersistenceType) = 0;
    221 };
    222 
    223 class OriginUsageHelper : public CancelableHelper {
    224 protected:
    225  mozilla::Result<UsageInfo, nsresult> GetUsageForOrigin(
    226      QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
    227      const OriginMetadata& aOriginMetadata);
    228 
    229 private:
    230  mozilla::Result<UsageInfo, nsresult> GetUsageForOriginEntries(
    231      QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
    232      const OriginMetadata& aOriginMetadata, nsIFile& aDirectory,
    233      bool aInitialized);
    234 };
    235 
    236 class GetUsageOp final
    237    : public OpenStorageDirectoryHelper<
    238          ResolvableNormalOriginOp<OriginUsageMetadataArray, true>>,
    239      public TraverseRepositoryHelper,
    240      public OriginUsageHelper {
    241  OriginUsageMetadataArray mOriginUsages;
    242  nsTHashMap<nsCStringHashKey, uint32_t> mOriginUsagesIndex;
    243 
    244  bool mGetAll;
    245 
    246 public:
    247  GetUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, bool aGetAll);
    248 
    249 private:
    250  ~GetUsageOp() = default;
    251 
    252  void ProcessOriginInternal(QuotaManager* aQuotaManager,
    253                             const PersistenceType aPersistenceType,
    254                             const nsACString& aOrigin,
    255                             const int64_t aTimestamp, const bool aPersisted,
    256                             const uint64_t aUsage);
    257 
    258  RefPtr<BoolPromise> OpenDirectory() override;
    259 
    260  const Atomic<bool>& GetIsCanceledFlag() override;
    261 
    262  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    263 
    264  nsresult ProcessOrigin(QuotaManager& aQuotaManager, nsIFile& aOriginDir,
    265                         const bool aPersistent,
    266                         const PersistenceType aPersistenceType) override;
    267 
    268  OriginUsageMetadataArray UnwrapResolveValue() override;
    269 
    270  void CloseDirectory() override;
    271 };
    272 
    273 class GetOriginUsageOp final
    274    : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<UsageInfo>>,
    275      public OriginUsageHelper {
    276  const PrincipalInfo mPrincipalInfo;
    277  PrincipalMetadata mPrincipalMetadata;
    278  UsageInfo mUsageInfo;
    279 
    280 public:
    281  GetOriginUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    282                   const PrincipalInfo& aPrincipalInfo);
    283 
    284 private:
    285  ~GetOriginUsageOp() = default;
    286 
    287  nsresult DoInit(QuotaManager& aQuotaManager) override;
    288 
    289  RefPtr<BoolPromise> OpenDirectory() override;
    290 
    291  virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    292 
    293  const Atomic<bool>& GetIsCanceledFlag() override;
    294 
    295  UsageInfo UnwrapResolveValue() override;
    296 
    297  void CloseDirectory() override;
    298 };
    299 
    300 class StorageNameOp final : public QuotaRequestBase {
    301  nsString mName;
    302 
    303 public:
    304  explicit StorageNameOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
    305 
    306 private:
    307  ~StorageNameOp() = default;
    308 
    309  RefPtr<BoolPromise> OpenDirectory() override;
    310 
    311  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    312 
    313  void GetResponse(RequestResponse& aResponse) override;
    314 
    315  void CloseDirectory() override;
    316 };
    317 
    318 class InitializedRequestBase : public ResolvableNormalOriginOp<bool> {
    319 protected:
    320  bool mInitialized;
    321 
    322  InitializedRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    323                         const char* aName);
    324 
    325 private:
    326  RefPtr<BoolPromise> OpenDirectory() override;
    327 
    328  void CloseDirectory() override;
    329 };
    330 
    331 class StorageInitializedOp final : public InitializedRequestBase {
    332 public:
    333  explicit StorageInitializedOp(
    334      MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
    335      : InitializedRequestBase(std::move(aQuotaManager),
    336                               "dom::quota::StorageInitializedOp") {}
    337 
    338 private:
    339  ~StorageInitializedOp() = default;
    340 
    341  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    342 
    343  bool UnwrapResolveValue() override;
    344 };
    345 
    346 class PersistentStorageInitializedOp final : public InitializedRequestBase {
    347 public:
    348  explicit PersistentStorageInitializedOp(
    349      MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
    350      : InitializedRequestBase(std::move(aQuotaManager),
    351                               "dom::quota::PersistentStorageInitializedOp") {}
    352 
    353 private:
    354  ~PersistentStorageInitializedOp() = default;
    355 
    356  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    357 
    358  bool UnwrapResolveValue() override;
    359 };
    360 
    361 class TemporaryStorageInitializedOp final : public InitializedRequestBase {
    362 public:
    363  explicit TemporaryStorageInitializedOp(
    364      MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
    365      : InitializedRequestBase(std::move(aQuotaManager),
    366                               "dom::quota::TemporaryStorageInitializedOp") {}
    367 
    368 private:
    369  ~TemporaryStorageInitializedOp() = default;
    370 
    371  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    372 
    373  bool UnwrapResolveValue() override;
    374 };
    375 
    376 class TemporaryGroupInitializedOp final
    377    : public ResolvableNormalOriginOp<bool> {
    378  const PrincipalMetadata mPrincipalMetadata;
    379  bool mInitialized;
    380 
    381 public:
    382  explicit TemporaryGroupInitializedOp(
    383      MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    384      const PrincipalMetadata& aPrincipalMetadata);
    385 
    386 private:
    387  ~TemporaryGroupInitializedOp() = default;
    388 
    389  RefPtr<BoolPromise> OpenDirectory() override;
    390 
    391  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    392 
    393  bool UnwrapResolveValue() override;
    394 
    395  void CloseDirectory() override;
    396 };
    397 
    398 class InitializedOriginRequestBase : public ResolvableNormalOriginOp<bool> {
    399 protected:
    400  const PrincipalMetadata mPrincipalMetadata;
    401  bool mInitialized;
    402 
    403  InitializedOriginRequestBase(
    404      MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
    405      const PrincipalMetadata& aPrincipalMetadata);
    406 
    407 private:
    408  RefPtr<BoolPromise> OpenDirectory() override;
    409 
    410  void CloseDirectory() override;
    411 };
    412 
    413 class PersistentOriginInitializedOp final
    414    : public InitializedOriginRequestBase {
    415 public:
    416  explicit PersistentOriginInitializedOp(
    417      MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    418      const OriginMetadata& aOriginMetadata);
    419 
    420 private:
    421  ~PersistentOriginInitializedOp() = default;
    422 
    423  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    424 
    425  bool UnwrapResolveValue() override;
    426 };
    427 
    428 class TemporaryOriginInitializedOp final : public InitializedOriginRequestBase {
    429  const PersistenceType mPersistenceType;
    430 
    431 public:
    432  explicit TemporaryOriginInitializedOp(
    433      MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    434      const OriginMetadata& aOriginMetadata);
    435 
    436 private:
    437  ~TemporaryOriginInitializedOp() = default;
    438 
    439  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    440 
    441  bool UnwrapResolveValue() override;
    442 };
    443 
    444 class InitOp final : public ResolvableNormalOriginOp<bool> {
    445  RefPtr<UniversalDirectoryLock> mDirectoryLock;
    446 
    447 public:
    448  InitOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    449         RefPtr<UniversalDirectoryLock> aDirectoryLock);
    450 
    451 private:
    452  ~InitOp() = default;
    453 
    454  RefPtr<BoolPromise> OpenDirectory() override;
    455 
    456  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    457 
    458  bool UnwrapResolveValue() override;
    459 
    460  void CloseDirectory() override;
    461 };
    462 
    463 class InitializePersistentStorageOp final
    464    : public ResolvableNormalOriginOp<bool> {
    465  RefPtr<UniversalDirectoryLock> mDirectoryLock;
    466 
    467 public:
    468  InitializePersistentStorageOp(
    469      MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    470      RefPtr<UniversalDirectoryLock> aDirectoryLock);
    471 
    472 private:
    473  ~InitializePersistentStorageOp() = default;
    474 
    475  RefPtr<BoolPromise> OpenDirectory() override;
    476 
    477  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    478 
    479  bool UnwrapResolveValue() override;
    480 
    481  void CloseDirectory() override;
    482 };
    483 
    484 class InitTemporaryStorageOp final
    485    : public ResolvableNormalOriginOp<MaybePrincipalMetadataArray, true> {
    486  MaybePrincipalMetadataArray mAllTemporaryGroups;
    487  RefPtr<UniversalDirectoryLock> mDirectoryLock;
    488 
    489 public:
    490  InitTemporaryStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    491                         RefPtr<UniversalDirectoryLock> aDirectoryLock);
    492 
    493 private:
    494  ~InitTemporaryStorageOp() = default;
    495 
    496  RefPtr<BoolPromise> OpenDirectory() override;
    497 
    498  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    499 
    500  MaybePrincipalMetadataArray UnwrapResolveValue() override;
    501 
    502  void CloseDirectory() override;
    503 };
    504 
    505 class InitializeTemporaryGroupOp final : public ResolvableNormalOriginOp<bool> {
    506  const PrincipalMetadata mPrincipalMetadata;
    507  RefPtr<UniversalDirectoryLock> mDirectoryLock;
    508 
    509 public:
    510  InitializeTemporaryGroupOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    511                             const PrincipalMetadata& aPrincipalMetadata,
    512                             RefPtr<UniversalDirectoryLock> aDirectoryLock);
    513 
    514 private:
    515  ~InitializeTemporaryGroupOp() = default;
    516 
    517  RefPtr<BoolPromise> OpenDirectory() override;
    518 
    519  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    520 
    521  bool UnwrapResolveValue() override;
    522 
    523  void CloseDirectory() override;
    524 };
    525 
    526 class InitializeOriginRequestBase : public ResolvableNormalOriginOp<bool> {
    527 protected:
    528  const PrincipalMetadata mPrincipalMetadata;
    529  RefPtr<UniversalDirectoryLock> mDirectoryLock;
    530  bool mCreated;
    531 
    532  InitializeOriginRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    533                              const char* aName,
    534                              const PrincipalMetadata& aPrincipalMetadata,
    535                              RefPtr<UniversalDirectoryLock> aDirectoryLock);
    536 
    537 private:
    538  RefPtr<BoolPromise> OpenDirectory() override;
    539 
    540  void CloseDirectory() override;
    541 };
    542 
    543 class InitializePersistentOriginOp final : public InitializeOriginRequestBase {
    544 public:
    545  InitializePersistentOriginOp(
    546      MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    547      const OriginMetadata& aOriginMetadata,
    548      RefPtr<UniversalDirectoryLock> aDirectoryLock);
    549 
    550 private:
    551  ~InitializePersistentOriginOp() = default;
    552 
    553  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    554 
    555  bool UnwrapResolveValue() override;
    556 };
    557 
    558 class InitializeTemporaryOriginOp final : public InitializeOriginRequestBase {
    559  const PersistenceType mPersistenceType;
    560  const bool mCreateIfNonExistent;
    561 
    562 public:
    563  InitializeTemporaryOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    564                              const OriginMetadata& aOriginMetadata,
    565                              bool aCreateIfNonExistent,
    566                              RefPtr<UniversalDirectoryLock> aDirectoryLock);
    567 
    568 private:
    569  ~InitializeTemporaryOriginOp() = default;
    570 
    571  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    572 
    573  bool UnwrapResolveValue() override;
    574 };
    575 
    576 class InitializeClientBase : public ResolvableNormalOriginOp<bool> {
    577 protected:
    578  const ClientMetadata mClientMetadata;
    579  RefPtr<UniversalDirectoryLock> mDirectoryLock;
    580  bool mCreated;
    581 
    582  InitializeClientBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    583                       const char* aName, const ClientMetadata& aClientMetadata,
    584                       RefPtr<UniversalDirectoryLock> aDirectoryLock);
    585 
    586 private:
    587  RefPtr<BoolPromise> OpenDirectory() override;
    588 
    589  void CloseDirectory() override;
    590 };
    591 
    592 class InitializePersistentClientOp : public InitializeClientBase {
    593 public:
    594  InitializePersistentClientOp(
    595      MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    596      const ClientMetadata& aClientMetadata,
    597      RefPtr<UniversalDirectoryLock> aDirectoryLock);
    598 
    599 private:
    600  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    601 
    602  bool UnwrapResolveValue() override;
    603 };
    604 
    605 class InitializeTemporaryClientOp : public InitializeClientBase {
    606  const bool mCreateIfNonExistent;
    607 
    608 public:
    609  InitializeTemporaryClientOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    610                              const ClientMetadata& aClientMetadata,
    611                              bool aCreateIfNonExistent,
    612                              RefPtr<UniversalDirectoryLock> aDirectoryLock);
    613 
    614 private:
    615  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    616 
    617  bool UnwrapResolveValue() override;
    618 };
    619 
    620 class GetFullOriginMetadataOp
    621    : public OpenStorageDirectoryHelper<QuotaRequestBase> {
    622  const GetFullOriginMetadataParams mParams;
    623  // XXX Consider wrapping with LazyInitializedOnce
    624  OriginMetadata mOriginMetadata;
    625  Maybe<FullOriginMetadata> mMaybeFullOriginMetadata;
    626 
    627 public:
    628  GetFullOriginMetadataOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    629                          const GetFullOriginMetadataParams& aParams);
    630 
    631 private:
    632  nsresult DoInit(QuotaManager& aQuotaManager) override;
    633 
    634  RefPtr<BoolPromise> OpenDirectory() override;
    635 
    636  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    637 
    638  void GetResponse(RequestResponse& aResponse) override;
    639 
    640  void CloseDirectory() override;
    641 };
    642 
    643 class GetCachedOriginUsageOp
    644    : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<uint64_t>> {
    645  const PrincipalInfo mPrincipalInfo;
    646  PrincipalMetadata mPrincipalMetadata;
    647  uint64_t mUsage;
    648 
    649 public:
    650  GetCachedOriginUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    651                         const PrincipalInfo& aPrincipalInfo);
    652 
    653 private:
    654  ~GetCachedOriginUsageOp() = default;
    655 
    656  nsresult DoInit(QuotaManager& aQuotaManager) override;
    657 
    658  RefPtr<BoolPromise> OpenDirectory() override;
    659 
    660  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    661 
    662  uint64_t UnwrapResolveValue() override;
    663 
    664  void CloseDirectory() override;
    665 };
    666 
    667 class ListCachedOriginsOp final
    668    : public OpenStorageDirectoryHelper<
    669          ResolvableNormalOriginOp<CStringArray, /* IsExclusive */ true>> {
    670  nsTArray<nsCString> mOrigins;
    671 
    672 public:
    673  explicit ListCachedOriginsOp(
    674      MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
    675 
    676 private:
    677  ~ListCachedOriginsOp() = default;
    678 
    679  RefPtr<BoolPromise> OpenDirectory() override;
    680 
    681  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    682 
    683  CStringArray UnwrapResolveValue() override;
    684 
    685  void CloseDirectory() override;
    686 };
    687 
    688 class ClearStorageOp final
    689    : public OpenStorageDirectoryHelper<ResolvableNormalOriginOp<bool>> {
    690 public:
    691  explicit ClearStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
    692 
    693 private:
    694  ~ClearStorageOp() = default;
    695 
    696  void DeleteFiles(QuotaManager& aQuotaManager);
    697 
    698  void DeleteStorageFile(QuotaManager& aQuotaManager);
    699 
    700  RefPtr<BoolPromise> OpenDirectory() override;
    701 
    702  virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    703 
    704  bool UnwrapResolveValue() override;
    705 
    706  void CloseDirectory() override;
    707 };
    708 
    709 class ClearRequestBase
    710    : public OpenStorageDirectoryHelper<
    711          ResolvableNormalOriginOp<OriginMetadataArray, true>> {
    712  Atomic<uint64_t> mIterations;
    713 
    714 protected:
    715  OriginMetadataArray mOriginMetadataArray;
    716 
    717  ClearRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    718                   const char* aName)
    719      : OpenStorageDirectoryHelper(std::move(aQuotaManager), aName),
    720        mIterations(0) {
    721    AssertIsOnOwningThread();
    722  }
    723 
    724  void DeleteFiles(QuotaManager& aQuotaManager,
    725                   const OriginMetadata& aOriginMetadata);
    726 
    727  void DeleteFiles(QuotaManager& aQuotaManager,
    728                   PersistenceType aPersistenceType,
    729                   const OriginScope& aOriginScope);
    730 
    731 private:
    732  template <typename FileCollector>
    733  void DeleteFilesInternal(QuotaManager& aQuotaManager,
    734                           PersistenceType aPersistenceType,
    735                           const OriginScope& aOriginScope,
    736                           const FileCollector& aFileCollector);
    737 
    738  void DoStringify(nsACString& aData) override {
    739    aData.Append("ClearRequestBase "_ns +
    740                 //
    741                 kStringifyStartInstance +
    742                 //
    743                 "Iterations:"_ns +
    744                 IntToCString(static_cast<uint64_t>(mIterations)) +
    745                 //
    746                 kStringifyEndInstance);
    747  }
    748 };
    749 
    750 class ClearOriginOp final : public ClearRequestBase {
    751  const PrincipalInfo mPrincipalInfo;
    752  PrincipalMetadata mPrincipalMetadata;
    753  const PersistenceScope mPersistenceScope;
    754 
    755 public:
    756  ClearOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    757                const mozilla::Maybe<PersistenceType>& aPersistenceType,
    758                const PrincipalInfo& aPrincipalInfo);
    759 
    760 private:
    761  ~ClearOriginOp() = default;
    762 
    763  nsresult DoInit(QuotaManager& aQuotaManager) override;
    764 
    765  RefPtr<BoolPromise> OpenDirectory() override;
    766 
    767  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    768 
    769  OriginMetadataArray UnwrapResolveValue() override;
    770 
    771  void CloseDirectory() override;
    772 };
    773 
    774 class ClearClientOp final
    775    : public OpenStorageDirectoryHelper<
    776          ResolvableNormalOriginOp<ClientMetadataArray, true>> {
    777  const PrincipalInfo mPrincipalInfo;
    778  PrincipalMetadata mPrincipalMetadata;
    779  ClientMetadataArray mClientMetadataArray;
    780  const PersistenceScope mPersistenceScope;
    781  const Client::Type mClientType;
    782 
    783 public:
    784  ClearClientOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    785                mozilla::Maybe<PersistenceType> aPersistenceType,
    786                const PrincipalInfo& aPrincipalInfo,
    787                const Client::Type aClientType);
    788 
    789 private:
    790  ~ClearClientOp() = default;
    791 
    792  nsresult DoInit(QuotaManager& aQuotaManager) override;
    793 
    794  RefPtr<BoolPromise> OpenDirectory() override;
    795 
    796  void DeleteFiles(const ClientMetadata& aClientMetadata);
    797 
    798  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    799 
    800  ClientMetadataArray UnwrapResolveValue() override;
    801 
    802  void CloseDirectory() override;
    803 };
    804 
    805 class ClearStoragesForOriginPrefixOp final
    806    : public OpenStorageDirectoryHelper<ClearRequestBase> {
    807  const PrincipalInfo mPrincipalInfo;
    808  PrincipalMetadata mPrincipalMetadata;
    809  const PersistenceScope mPersistenceScope;
    810 
    811 public:
    812  ClearStoragesForOriginPrefixOp(
    813      MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    814      const Maybe<PersistenceType>& aPersistenceType,
    815      const PrincipalInfo& aPrincipalInfo);
    816 
    817 private:
    818  ~ClearStoragesForOriginPrefixOp() = default;
    819 
    820  nsresult DoInit(QuotaManager& aQuotaManager) override;
    821 
    822  RefPtr<BoolPromise> OpenDirectory() override;
    823 
    824  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    825 
    826  OriginMetadataArray UnwrapResolveValue() override;
    827 
    828  void CloseDirectory() override;
    829 };
    830 
    831 class ClearDataOp final : public ClearRequestBase {
    832  const OriginAttributesPattern mPattern;
    833 
    834 public:
    835  ClearDataOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    836              const OriginAttributesPattern& aPattern);
    837 
    838 private:
    839  ~ClearDataOp() = default;
    840 
    841  RefPtr<BoolPromise> OpenDirectory() override;
    842 
    843  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    844 
    845  OriginMetadataArray UnwrapResolveValue() override;
    846 
    847  void CloseDirectory() override;
    848 };
    849 
    850 class ShutdownOriginOp final
    851    : public ResolvableNormalOriginOp<OriginMetadataArray, true> {
    852  const PrincipalInfo mPrincipalInfo;
    853  PrincipalMetadata mPrincipalMetadata;
    854  OriginMetadataArray mOriginMetadataArray;
    855  RefPtr<UniversalDirectoryLock> mDirectoryLock;
    856  const PersistenceScope mPersistenceScope;
    857 
    858 public:
    859  ShutdownOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    860                   mozilla::Maybe<PersistenceType> aPersistenceType,
    861                   const PrincipalInfo& aPrincipalInfo);
    862 
    863 private:
    864  ~ShutdownOriginOp() = default;
    865 
    866  nsresult DoInit(QuotaManager& aQuotaManager) override;
    867 
    868  RefPtr<BoolPromise> OpenDirectory() override;
    869 
    870  void CollectOriginMetadata(const OriginMetadata& aOriginMetadata);
    871 
    872  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    873 
    874  OriginMetadataArray UnwrapResolveValue() override;
    875 
    876  void CloseDirectory() override;
    877 };
    878 
    879 class ShutdownClientOp final
    880    : public ResolvableNormalOriginOp<ClientMetadataArray, true> {
    881  const PrincipalInfo mPrincipalInfo;
    882  PrincipalMetadata mPrincipalMetadata;
    883  ClientMetadataArray mClientMetadataArray;
    884  RefPtr<UniversalDirectoryLock> mDirectoryLock;
    885  const PersistenceScope mPersistenceScope;
    886  const Client::Type mClientType;
    887 
    888 public:
    889  ShutdownClientOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    890                   mozilla::Maybe<PersistenceType> aPersistenceType,
    891                   const PrincipalInfo& aPrincipalInfo,
    892                   const Client::Type aClientType);
    893 
    894 private:
    895  ~ShutdownClientOp() = default;
    896 
    897  nsresult DoInit(QuotaManager& aQuotaManager) override;
    898 
    899  RefPtr<BoolPromise> OpenDirectory() override;
    900 
    901  void CollectOriginMetadata(const ClientMetadata& aClientMetadata);
    902 
    903  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    904 
    905  ClientMetadataArray UnwrapResolveValue() override;
    906 
    907  void CloseDirectory() override;
    908 };
    909 
    910 class PersistRequestBase : public OpenStorageDirectoryHelper<QuotaRequestBase> {
    911  const PrincipalInfo mPrincipalInfo;
    912 
    913 protected:
    914  PrincipalMetadata mPrincipalMetadata;
    915 
    916 protected:
    917  PersistRequestBase(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    918                     const PrincipalInfo& aPrincipalInfo);
    919 
    920  nsresult DoInit(QuotaManager& aQuotaManager) override;
    921 
    922 private:
    923  RefPtr<BoolPromise> OpenDirectory() override;
    924 
    925  void CloseDirectory() override;
    926 };
    927 
    928 class PersistedOp final : public PersistRequestBase {
    929  bool mPersisted;
    930 
    931 public:
    932  PersistedOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    933              const RequestParams& aParams);
    934 
    935 private:
    936  ~PersistedOp() = default;
    937 
    938  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    939 
    940  void GetResponse(RequestResponse& aResponse) override;
    941 };
    942 
    943 class PersistOp final : public PersistRequestBase {
    944 public:
    945  PersistOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    946            const RequestParams& aParams);
    947 
    948 private:
    949  ~PersistOp() = default;
    950 
    951  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    952 
    953  void GetResponse(RequestResponse& aResponse) override;
    954 };
    955 
    956 class EstimateOp final : public OpenStorageDirectoryHelper<QuotaRequestBase> {
    957  const EstimateParams mParams;
    958  OriginMetadata mOriginMetadata;
    959  std::pair<uint64_t, uint64_t> mUsageAndLimit;
    960 
    961 public:
    962  EstimateOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
    963             const EstimateParams& aParams);
    964 
    965 private:
    966  ~EstimateOp() = default;
    967 
    968  nsresult DoInit(QuotaManager& aQuotaManager) override;
    969 
    970  RefPtr<BoolPromise> OpenDirectory() override;
    971 
    972  virtual nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    973 
    974  void GetResponse(RequestResponse& aResponse) override;
    975 
    976  void CloseDirectory() override;
    977 };
    978 
    979 class ListOriginsOp final
    980    : public OpenStorageDirectoryHelper<
    981          ResolvableNormalOriginOp<CStringArray, /* IsExclusive */ true>>,
    982      public TraverseRepositoryHelper {
    983  // XXX Bug 1521541 will make each origin has it's own state.
    984  nsTArray<nsCString> mOrigins;
    985 
    986 public:
    987  explicit ListOriginsOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager);
    988 
    989 private:
    990  ~ListOriginsOp() = default;
    991 
    992  RefPtr<BoolPromise> OpenDirectory() override;
    993 
    994  nsresult DoDirectoryWork(QuotaManager& aQuotaManager) override;
    995 
    996  const Atomic<bool>& GetIsCanceledFlag() override;
    997 
    998  nsresult ProcessOrigin(QuotaManager& aQuotaManager, nsIFile& aOriginDir,
    999                         const bool aPersistent,
   1000                         const PersistenceType aPersistenceType) override;
   1001 
   1002  CStringArray UnwrapResolveValue() override;
   1003 
   1004  void CloseDirectory() override;
   1005 };
   1006 
   1007 RefPtr<OriginOperationBase> CreateFinalizeOriginEvictionOp(
   1008    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1009    nsTArray<RefPtr<OriginDirectoryLock>>&& aLocks) {
   1010  return MakeRefPtr<FinalizeOriginEvictionOp>(std::move(aQuotaManager),
   1011                                              std::move(aLocks));
   1012 }
   1013 
   1014 RefPtr<UniversalDirectoryLock> CreateSaveOriginAccessTimeLock(
   1015    QuotaManager& aQuotaManager, const OriginMetadata& aOriginMetadata) {
   1016  RefPtr<UniversalDirectoryLock> directoryLock =
   1017      aQuotaManager.CreateDirectoryLockInternal(
   1018          PersistenceScope::CreateFromValue(aOriginMetadata.mPersistenceType),
   1019          OriginScope::FromOrigin(aOriginMetadata),
   1020          ClientStorageScope::CreateFromMetadata(), /* aExclusive */ false);
   1021 
   1022  return directoryLock;
   1023 }
   1024 
   1025 RefPtr<ResolvableNormalOriginOp<bool>> CreateSaveOriginAccessTimeOp(
   1026    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1027    const OriginMetadata& aOriginMetadata,
   1028    RefPtr<UniversalDirectoryLock> aDirectoryLock) {
   1029  return MakeRefPtr<SaveOriginAccessTimeOp>(std::move(aQuotaManager),
   1030                                            aOriginMetadata, aDirectoryLock);
   1031 }
   1032 
   1033 RefPtr<ResolvableNormalOriginOp<bool>> CreateClearPrivateRepositoryOp(
   1034    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
   1035  return MakeRefPtr<ClearPrivateRepositoryOp>(std::move(aQuotaManager));
   1036 }
   1037 
   1038 RefPtr<ResolvableNormalOriginOp<bool>> CreateShutdownStorageOp(
   1039    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
   1040  return MakeRefPtr<ShutdownStorageOp>(std::move(aQuotaManager));
   1041 }
   1042 
   1043 RefPtr<ResolvableNormalOriginOp<OriginUsageMetadataArray, true>>
   1044 CreateGetUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1045                 bool aGetAll) {
   1046  return MakeRefPtr<GetUsageOp>(std::move(aQuotaManager), aGetAll);
   1047 }
   1048 
   1049 RefPtr<ResolvableNormalOriginOp<UsageInfo>> CreateGetOriginUsageOp(
   1050    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1051    const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
   1052  return MakeRefPtr<GetOriginUsageOp>(std::move(aQuotaManager), aPrincipalInfo);
   1053 }
   1054 
   1055 RefPtr<QuotaRequestBase> CreateStorageNameOp(
   1056    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
   1057  return MakeRefPtr<StorageNameOp>(std::move(aQuotaManager));
   1058 }
   1059 
   1060 RefPtr<ResolvableNormalOriginOp<bool>> CreateStorageInitializedOp(
   1061    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
   1062  return MakeRefPtr<StorageInitializedOp>(std::move(aQuotaManager));
   1063 }
   1064 
   1065 RefPtr<ResolvableNormalOriginOp<bool>> CreatePersistentStorageInitializedOp(
   1066    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
   1067  return MakeRefPtr<PersistentStorageInitializedOp>(std::move(aQuotaManager));
   1068 }
   1069 
   1070 RefPtr<ResolvableNormalOriginOp<bool>> CreateTemporaryStorageInitializedOp(
   1071    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
   1072  return MakeRefPtr<TemporaryStorageInitializedOp>(std::move(aQuotaManager));
   1073 }
   1074 
   1075 RefPtr<ResolvableNormalOriginOp<bool>> CreateTemporaryGroupInitializedOp(
   1076    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1077    const PrincipalMetadata& aPrincipalMetadata) {
   1078  return MakeRefPtr<TemporaryGroupInitializedOp>(std::move(aQuotaManager),
   1079                                                 aPrincipalMetadata);
   1080 }
   1081 
   1082 RefPtr<ResolvableNormalOriginOp<bool>> CreatePersistentOriginInitializedOp(
   1083    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1084    const OriginMetadata& aOriginMetadata) {
   1085  return MakeRefPtr<PersistentOriginInitializedOp>(std::move(aQuotaManager),
   1086                                                   aOriginMetadata);
   1087 }
   1088 
   1089 RefPtr<ResolvableNormalOriginOp<bool>> CreateTemporaryOriginInitializedOp(
   1090    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1091    const OriginMetadata& aOriginMetadata) {
   1092  return MakeRefPtr<TemporaryOriginInitializedOp>(std::move(aQuotaManager),
   1093                                                  aOriginMetadata);
   1094 }
   1095 
   1096 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitOp(
   1097    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1098    RefPtr<UniversalDirectoryLock> aDirectoryLock) {
   1099  return MakeRefPtr<InitOp>(std::move(aQuotaManager),
   1100                            std::move(aDirectoryLock));
   1101 }
   1102 
   1103 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializePersistentStorageOp(
   1104    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1105    RefPtr<UniversalDirectoryLock> aDirectoryLock) {
   1106  return MakeRefPtr<InitializePersistentStorageOp>(std::move(aQuotaManager),
   1107                                                   std::move(aDirectoryLock));
   1108 }
   1109 
   1110 RefPtr<ResolvableNormalOriginOp<MaybePrincipalMetadataArray, true>>
   1111 CreateInitTemporaryStorageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1112                             RefPtr<UniversalDirectoryLock> aDirectoryLock) {
   1113  return MakeRefPtr<InitTemporaryStorageOp>(std::move(aQuotaManager),
   1114                                            std::move(aDirectoryLock));
   1115 }
   1116 
   1117 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializeTemporaryGroupOp(
   1118    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1119    const PrincipalMetadata& aPrincipalMetadata,
   1120    RefPtr<UniversalDirectoryLock> aDirectoryLock) {
   1121  return MakeRefPtr<InitializeTemporaryGroupOp>(
   1122      std::move(aQuotaManager), aPrincipalMetadata, std::move(aDirectoryLock));
   1123 }
   1124 
   1125 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializePersistentOriginOp(
   1126    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1127    const OriginMetadata& aOriginMetadata,
   1128    RefPtr<UniversalDirectoryLock> aDirectoryLock) {
   1129  return MakeRefPtr<InitializePersistentOriginOp>(
   1130      std::move(aQuotaManager), aOriginMetadata, std::move(aDirectoryLock));
   1131 }
   1132 
   1133 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializeTemporaryOriginOp(
   1134    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1135    const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent,
   1136    RefPtr<UniversalDirectoryLock> aDirectoryLock) {
   1137  return MakeRefPtr<InitializeTemporaryOriginOp>(
   1138      std::move(aQuotaManager), aOriginMetadata, aCreateIfNonExistent,
   1139      std::move(aDirectoryLock));
   1140 }
   1141 
   1142 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializePersistentClientOp(
   1143    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1144    const ClientMetadata& aClientMetadata,
   1145    RefPtr<UniversalDirectoryLock> aDirectoryLock) {
   1146  return MakeRefPtr<InitializePersistentClientOp>(
   1147      std::move(aQuotaManager), aClientMetadata, std::move(aDirectoryLock));
   1148 }
   1149 
   1150 RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializeTemporaryClientOp(
   1151    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1152    const ClientMetadata& aClientMetadata, bool aCreateIfNonExistent,
   1153    RefPtr<UniversalDirectoryLock> aDirectoryLock) {
   1154  return MakeRefPtr<InitializeTemporaryClientOp>(
   1155      std::move(aQuotaManager), aClientMetadata, aCreateIfNonExistent,
   1156      std::move(aDirectoryLock));
   1157 }
   1158 
   1159 RefPtr<QuotaRequestBase> CreateGetFullOriginMetadataOp(
   1160    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1161    const GetFullOriginMetadataParams& aParams) {
   1162  return MakeRefPtr<GetFullOriginMetadataOp>(std::move(aQuotaManager), aParams);
   1163 }
   1164 
   1165 RefPtr<ResolvableNormalOriginOp<uint64_t>> CreateGetCachedOriginUsageOp(
   1166    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1167    const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
   1168  return MakeRefPtr<GetCachedOriginUsageOp>(std::move(aQuotaManager),
   1169                                            aPrincipalInfo);
   1170 }
   1171 
   1172 RefPtr<ResolvableNormalOriginOp<CStringArray, true>> CreateListCachedOriginsOp(
   1173    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
   1174  return MakeRefPtr<ListCachedOriginsOp>(std::move(aQuotaManager));
   1175 }
   1176 
   1177 RefPtr<ResolvableNormalOriginOp<bool>> CreateClearStorageOp(
   1178    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
   1179  return MakeRefPtr<ClearStorageOp>(std::move(aQuotaManager));
   1180 }
   1181 
   1182 RefPtr<ResolvableNormalOriginOp<OriginMetadataArray, true>> CreateClearOriginOp(
   1183    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1184    const Maybe<PersistenceType>& aPersistenceType,
   1185    const PrincipalInfo& aPrincipalInfo) {
   1186  return MakeRefPtr<ClearOriginOp>(std::move(aQuotaManager), aPersistenceType,
   1187                                   aPrincipalInfo);
   1188 }
   1189 
   1190 RefPtr<ResolvableNormalOriginOp<ClientMetadataArray, true>> CreateClearClientOp(
   1191    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1192    Maybe<PersistenceType> aPersistenceType,
   1193    const PrincipalInfo& aPrincipalInfo, Client::Type aClientType) {
   1194  return MakeRefPtr<ClearClientOp>(std::move(aQuotaManager), aPersistenceType,
   1195                                   aPrincipalInfo, aClientType);
   1196 }
   1197 
   1198 RefPtr<ResolvableNormalOriginOp<OriginMetadataArray, true>>
   1199 CreateClearStoragesForOriginPrefixOp(
   1200    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1201    const Maybe<PersistenceType>& aPersistenceType,
   1202    const PrincipalInfo& aPrincipalInfo) {
   1203  return MakeRefPtr<ClearStoragesForOriginPrefixOp>(
   1204      std::move(aQuotaManager), aPersistenceType, aPrincipalInfo);
   1205 }
   1206 
   1207 RefPtr<ResolvableNormalOriginOp<OriginMetadataArray, true>> CreateClearDataOp(
   1208    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1209    const OriginAttributesPattern& aPattern) {
   1210  return MakeRefPtr<ClearDataOp>(std::move(aQuotaManager), aPattern);
   1211 }
   1212 
   1213 RefPtr<ResolvableNormalOriginOp<OriginMetadataArray, true>>
   1214 CreateShutdownOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1215                       Maybe<PersistenceType> aPersistenceType,
   1216                       const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
   1217  return MakeRefPtr<ShutdownOriginOp>(std::move(aQuotaManager),
   1218                                      aPersistenceType, aPrincipalInfo);
   1219 }
   1220 
   1221 RefPtr<ResolvableNormalOriginOp<ClientMetadataArray, true>>
   1222 CreateShutdownClientOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1223                       Maybe<PersistenceType> aPersistenceType,
   1224                       const PrincipalInfo& aPrincipalInfo,
   1225                       Client::Type aClientType) {
   1226  return MakeRefPtr<ShutdownClientOp>(
   1227      std::move(aQuotaManager), aPersistenceType, aPrincipalInfo, aClientType);
   1228 }
   1229 
   1230 RefPtr<QuotaRequestBase> CreatePersistedOp(
   1231    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1232    const RequestParams& aParams) {
   1233  return MakeRefPtr<PersistedOp>(std::move(aQuotaManager), aParams);
   1234 }
   1235 
   1236 RefPtr<QuotaRequestBase> CreatePersistOp(
   1237    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1238    const RequestParams& aParams) {
   1239  return MakeRefPtr<PersistOp>(std::move(aQuotaManager), aParams);
   1240 }
   1241 
   1242 RefPtr<QuotaRequestBase> CreateEstimateOp(
   1243    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1244    const EstimateParams& aParams) {
   1245  return MakeRefPtr<EstimateOp>(std::move(aQuotaManager), aParams);
   1246 }
   1247 
   1248 RefPtr<ResolvableNormalOriginOp<CStringArray, /* IsExclusive */ true>>
   1249 CreateListOriginsOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager) {
   1250  return MakeRefPtr<ListOriginsOp>(std::move(aQuotaManager));
   1251 }
   1252 
   1253 template <class Base>
   1254 RefPtr<BoolPromise> OpenStorageDirectoryHelper<Base>::OpenStorageDirectory(
   1255    const PersistenceScope& aPersistenceScope, const OriginScope& aOriginScope,
   1256    const ClientStorageScope& aClientStorageScope, bool aExclusive,
   1257    bool aInitializeOrigins, const DirectoryLockCategory aCategory) {
   1258  return Base::mQuotaManager
   1259      ->OpenStorageDirectory(aPersistenceScope, aOriginScope,
   1260                             aClientStorageScope, aExclusive,
   1261                             aInitializeOrigins, aCategory)
   1262      ->Then(GetCurrentSerialEventTarget(), __func__,
   1263             [self = RefPtr(this)](
   1264                 UniversalDirectoryLockPromise::ResolveOrRejectValue&& aValue) {
   1265               if (aValue.IsReject()) {
   1266                 return BoolPromise::CreateAndReject(aValue.RejectValue(),
   1267                                                     __func__);
   1268               }
   1269 
   1270               self->mDirectoryLock = std::move(aValue.ResolveValue());
   1271 
   1272               return BoolPromise::CreateAndResolve(true, __func__);
   1273             });
   1274 }
   1275 
   1276 RefPtr<BoolPromise> FinalizeOriginEvictionOp::Open() {
   1277  AssertIsOnOwningThread();
   1278  MOZ_ASSERT(!mLocks.IsEmpty());
   1279 
   1280  return BoolPromise::CreateAndResolve(true, __func__);
   1281 }
   1282 
   1283 nsresult FinalizeOriginEvictionOp::DoDirectoryWork(
   1284    QuotaManager& aQuotaManager) {
   1285  AssertIsOnIOThread();
   1286 
   1287  AUTO_PROFILER_LABEL("FinalizeOriginEvictionOp::DoDirectoryWork", OTHER);
   1288 
   1289  for (const auto& lock : mLocks) {
   1290    aQuotaManager.OriginClearCompleted(lock->OriginMetadata(),
   1291                                       ClientStorageScope::CreateFromNull());
   1292  }
   1293 
   1294  return NS_OK;
   1295 }
   1296 
   1297 void FinalizeOriginEvictionOp::UnblockOpen() {
   1298  AssertIsOnOwningThread();
   1299 
   1300  nsTArray<OriginMetadata> origins;
   1301 
   1302  std::transform(mLocks.cbegin(), mLocks.cend(), MakeBackInserter(origins),
   1303                 [](const auto& lock) { return lock->OriginMetadata(); });
   1304 
   1305  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NS_NewRunnableFunction(
   1306      "dom::quota::FinalizeOriginEvictionOp::UnblockOpen",
   1307      [quotaManager = mQuotaManager, origins = std::move(origins)]() {
   1308        quotaManager->NoteUninitializedClients(origins);
   1309        quotaManager->NoteUninitializedOrigins(origins);
   1310      })));
   1311 
   1312  for (const auto& lock : mLocks) {
   1313    lock->Drop();
   1314  }
   1315  mLocks.Clear();
   1316 }
   1317 
   1318 RefPtr<BoolPromise> SaveOriginAccessTimeOp::OpenDirectory() {
   1319  AssertIsOnOwningThread();
   1320 
   1321  MOZ_ASSERT(mDirectoryLock);
   1322 
   1323  return BoolPromise::CreateAndResolve(true, __func__);
   1324 }
   1325 
   1326 nsresult SaveOriginAccessTimeOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   1327  AssertIsOnIOThread();
   1328 
   1329  AUTO_PROFILER_LABEL("SaveOriginAccessTimeOp::DoDirectoryWork", OTHER);
   1330 
   1331  QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
   1332         NS_ERROR_NOT_INITIALIZED);
   1333 
   1334  QM_TRY(OkIf(aQuotaManager.IsTemporaryStorageInitializedInternal()),
   1335         NS_ERROR_NOT_INITIALIZED);
   1336 
   1337  QM_TRY(
   1338      OkIf(aQuotaManager.IsTemporaryOriginInitializedInternal(mOriginMetadata)),
   1339      NS_ERROR_NOT_INITIALIZED);
   1340 
   1341  auto maybeOriginStateMetadata =
   1342      aQuotaManager.GetOriginStateMetadata(mOriginMetadata);
   1343 
   1344  auto originStateMetadata = maybeOriginStateMetadata.extract();
   1345 
   1346  // See the documentation for this pref in StaticPrefList.yaml
   1347  if (StaticPrefs::dom_quotaManager_temporaryStorage_updateOriginAccessTime()) {
   1348    originStateMetadata.mLastAccessTime = PR_Now();
   1349  }
   1350 
   1351  originStateMetadata.mAccessed = true;
   1352 
   1353  QM_TRY_INSPECT(const auto& file,
   1354                 aQuotaManager.GetOriginDirectory(mOriginMetadata));
   1355 
   1356  // The origin directory may not exist if the origin was initialized without
   1357  // ensuring the origin directory.
   1358 
   1359  QM_TRY_INSPECT(const bool& exists, MOZ_TO_RESULT_INVOKE_MEMBER(file, Exists));
   1360 
   1361  if (exists) {
   1362    QM_TRY(
   1363        MOZ_TO_RESULT(SaveDirectoryMetadataHeader(*file, originStateMetadata)));
   1364 
   1365    mSaved = true;
   1366 
   1367    aQuotaManager.IncreaseSaveOriginAccessTimeCountInternal();
   1368  }
   1369 
   1370  aQuotaManager.UpdateOriginAccessTime(mOriginMetadata,
   1371                                       originStateMetadata.mLastAccessTime);
   1372 
   1373  return NS_OK;
   1374 }
   1375 
   1376 bool SaveOriginAccessTimeOp::UnwrapResolveValue() { return mSaved; }
   1377 
   1378 void SaveOriginAccessTimeOp::CloseDirectory() {
   1379  AssertIsOnOwningThread();
   1380 
   1381  SafeDropDirectoryLock(mDirectoryLock);
   1382 }
   1383 
   1384 RefPtr<BoolPromise> ClearPrivateRepositoryOp::OpenDirectory() {
   1385  AssertIsOnOwningThread();
   1386 
   1387  return OpenStorageDirectory(
   1388      PersistenceScope::CreateFromValue(PERSISTENCE_TYPE_PRIVATE),
   1389      OriginScope::FromNull(), ClientStorageScope::CreateFromNull(),
   1390      /* aExclusive */ true, /* aInitializeOrigins */ false,
   1391      DirectoryLockCategory::UninitOrigins);
   1392 }
   1393 
   1394 nsresult ClearPrivateRepositoryOp::DoDirectoryWork(
   1395    QuotaManager& aQuotaManager) {
   1396  AssertIsOnIOThread();
   1397  aQuotaManager.AssertStorageIsInitializedInternal();
   1398 
   1399  AUTO_PROFILER_LABEL("ClearPrivateRepositoryOp::DoDirectoryWork", OTHER);
   1400 
   1401  QM_TRY_INSPECT(
   1402      const auto& directory,
   1403      QM_NewLocalFile(aQuotaManager.GetStoragePath(PERSISTENCE_TYPE_PRIVATE)));
   1404 
   1405  nsresult rv = directory->Remove(true);
   1406  if (rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
   1407    // This should never fail if we've closed all storage connections
   1408    // correctly...
   1409    MOZ_ASSERT(false, "Failed to remove directory!");
   1410  }
   1411 
   1412  aQuotaManager.RemoveQuotaForRepository(PERSISTENCE_TYPE_PRIVATE);
   1413 
   1414  aQuotaManager.RepositoryClearCompleted(PERSISTENCE_TYPE_PRIVATE);
   1415 
   1416  return NS_OK;
   1417 }
   1418 
   1419 void ClearPrivateRepositoryOp::CloseDirectory() {
   1420  AssertIsOnOwningThread();
   1421 
   1422  SafeDropDirectoryLock(mDirectoryLock);
   1423 }
   1424 
   1425 RefPtr<BoolPromise> ShutdownStorageOp::OpenDirectory() {
   1426  AssertIsOnOwningThread();
   1427 
   1428  mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
   1429      PersistenceScope::CreateFromNull(), OriginScope::FromNull(),
   1430      ClientStorageScope::CreateFromNull(),
   1431      /* aExclusive */ true, DirectoryLockCategory::UninitStorage);
   1432 
   1433  return mDirectoryLock->Acquire();
   1434 }
   1435 
   1436 #ifdef DEBUG
   1437 nsresult ShutdownStorageOp::DirectoryOpen() {
   1438  AssertIsOnBackgroundThread();
   1439  MOZ_ASSERT(mDirectoryLock);
   1440  mDirectoryLock->AssertIsAcquiredExclusively();
   1441 
   1442  return NormalOriginOperationBase::DirectoryOpen();
   1443 }
   1444 #endif
   1445 
   1446 nsresult ShutdownStorageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   1447  AssertIsOnIOThread();
   1448 
   1449  AUTO_PROFILER_LABEL("ShutdownStorageOp::DoDirectoryWork", OTHER);
   1450 
   1451  aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
   1452      "ShutdownStorageOp::DoDirectoryWork -> ShutdownStorageInternal."_ns);
   1453 
   1454  aQuotaManager.ShutdownStorageInternal();
   1455 
   1456  return NS_OK;
   1457 }
   1458 
   1459 void ShutdownStorageOp::CloseDirectory() {
   1460  AssertIsOnOwningThread();
   1461 
   1462  DropDirectoryLockIfNotDropped(mDirectoryLock);
   1463 }
   1464 
   1465 nsresult TraverseRepositoryHelper::TraverseRepository(
   1466    QuotaManager& aQuotaManager, PersistenceType aPersistenceType) {
   1467  AssertIsOnIOThread();
   1468 
   1469  QM_TRY_INSPECT(
   1470      const auto& directory,
   1471      QM_NewLocalFile(aQuotaManager.GetStoragePath(aPersistenceType)));
   1472 
   1473  QM_TRY_INSPECT(const bool& exists,
   1474                 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
   1475 
   1476  if (!exists) {
   1477    return NS_OK;
   1478  }
   1479 
   1480  QM_TRY(CollectEachFileAtomicCancelable(
   1481      *directory, GetIsCanceledFlag(),
   1482      [this, aPersistenceType, &aQuotaManager,
   1483       persistent = aPersistenceType == PERSISTENCE_TYPE_PERSISTENT](
   1484          const nsCOMPtr<nsIFile>& originDir) -> Result<Ok, nsresult> {
   1485        QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*originDir));
   1486 
   1487        switch (dirEntryKind) {
   1488          case nsIFileKind::ExistsAsDirectory:
   1489            QM_TRY(MOZ_TO_RESULT(ProcessOrigin(aQuotaManager, *originDir,
   1490                                               persistent, aPersistenceType)));
   1491            break;
   1492 
   1493          case nsIFileKind::ExistsAsFile: {
   1494            QM_TRY_INSPECT(const auto& leafName,
   1495                           MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
   1496                               nsAutoString, originDir, GetLeafName));
   1497 
   1498            // Unknown files during getting usages are allowed. Just warn if we
   1499            // find them.
   1500            if (!IsOSMetadata(leafName)) {
   1501              UNKNOWN_FILE_WARNING(leafName);
   1502            }
   1503 
   1504            break;
   1505          }
   1506 
   1507          case nsIFileKind::DoesNotExist:
   1508            // Ignore files that got removed externally while iterating.
   1509            break;
   1510        }
   1511 
   1512        return Ok{};
   1513      }));
   1514 
   1515  return NS_OK;
   1516 }
   1517 
   1518 Result<UsageInfo, nsresult> OriginUsageHelper::GetUsageForOrigin(
   1519    QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
   1520    const OriginMetadata& aOriginMetadata) {
   1521  AssertIsOnIOThread();
   1522  MOZ_ASSERT(aOriginMetadata.mPersistenceType == aPersistenceType);
   1523 
   1524  QM_TRY_INSPECT(const auto& directory,
   1525                 aQuotaManager.GetOriginDirectory(aOriginMetadata));
   1526 
   1527  QM_TRY_INSPECT(const bool& exists,
   1528                 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
   1529 
   1530  if (!exists || GetIsCanceledFlag()) {
   1531    return UsageInfo();
   1532  }
   1533 
   1534  // If the directory exists then enumerate all the files inside, adding up
   1535  // the sizes to get the final usage statistic.
   1536  bool initialized;
   1537 
   1538  if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
   1539    initialized = aQuotaManager.IsPersistentOriginInitializedInternal(
   1540        aOriginMetadata.mOrigin);
   1541  } else {
   1542    initialized = aQuotaManager.IsTemporaryStorageInitializedInternal();
   1543  }
   1544 
   1545  return GetUsageForOriginEntries(aQuotaManager, aPersistenceType,
   1546                                  aOriginMetadata, *directory, initialized);
   1547 }
   1548 
   1549 Result<UsageInfo, nsresult> OriginUsageHelper::GetUsageForOriginEntries(
   1550    QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
   1551    const OriginMetadata& aOriginMetadata, nsIFile& aDirectory,
   1552    const bool aInitialized) {
   1553  AssertIsOnIOThread();
   1554 
   1555  QM_TRY_RETURN((ReduceEachFileAtomicCancelable(
   1556      aDirectory, GetIsCanceledFlag(), UsageInfo{},
   1557      [&](UsageInfo oldUsageInfo, const nsCOMPtr<nsIFile>& file)
   1558          -> mozilla::Result<UsageInfo, nsresult> {
   1559        QM_TRY_INSPECT(
   1560            const auto& leafName,
   1561            MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, file, GetLeafName));
   1562 
   1563        QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*file));
   1564 
   1565        switch (dirEntryKind) {
   1566          case nsIFileKind::ExistsAsDirectory: {
   1567            Client::Type clientType;
   1568            const bool ok =
   1569                Client::TypeFromText(leafName, clientType, fallible);
   1570            if (!ok) {
   1571              // Unknown directories during getting usage for an origin (even
   1572              // for an uninitialized origin) are now allowed. Just warn if we
   1573              // find them.
   1574              UNKNOWN_FILE_WARNING(leafName);
   1575              break;
   1576            }
   1577 
   1578            Client* const client = aQuotaManager.GetClient(clientType);
   1579            MOZ_ASSERT(client);
   1580 
   1581            QM_TRY_INSPECT(const auto& usageInfo,
   1582                           aInitialized ? client->GetUsageForOrigin(
   1583                                              aPersistenceType, aOriginMetadata,
   1584                                              GetIsCanceledFlag())
   1585                                        : client->InitOrigin(
   1586                                              aPersistenceType, aOriginMetadata,
   1587                                              GetIsCanceledFlag()));
   1588            return oldUsageInfo + usageInfo;
   1589          }
   1590 
   1591          case nsIFileKind::ExistsAsFile:
   1592            // We are maintaining existing behavior for unknown files here (just
   1593            // continuing).
   1594            // This can possibly be used by developers to add temporary backups
   1595            // into origin directories without losing get usage functionality.
   1596            if (IsTempMetadata(leafName)) {
   1597              if (!aInitialized) {
   1598                QM_TRY(MOZ_TO_RESULT(file->Remove(/* recursive */ false)));
   1599              }
   1600 
   1601              break;
   1602            }
   1603 
   1604            if (IsOriginMetadata(leafName) || IsOSMetadata(leafName) ||
   1605                IsDotFile(leafName)) {
   1606              break;
   1607            }
   1608 
   1609            // Unknown files during getting usage for an origin (even for an
   1610            // uninitialized origin) are now allowed. Just warn if we find them.
   1611            UNKNOWN_FILE_WARNING(leafName);
   1612            break;
   1613 
   1614          case nsIFileKind::DoesNotExist:
   1615            // Ignore files that got removed externally while iterating.
   1616            break;
   1617        }
   1618 
   1619        return oldUsageInfo;
   1620      })));
   1621 }
   1622 
   1623 GetUsageOp::GetUsageOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1624                       bool aGetAll)
   1625    : OpenStorageDirectoryHelper(std::move(aQuotaManager),
   1626                                 "dom::quota::GetUsageOp"),
   1627      mGetAll(aGetAll) {
   1628  AssertIsOnOwningThread();
   1629 }
   1630 
   1631 void GetUsageOp::ProcessOriginInternal(QuotaManager* aQuotaManager,
   1632                                       const PersistenceType aPersistenceType,
   1633                                       const nsACString& aOrigin,
   1634                                       const int64_t aTimestamp,
   1635                                       const bool aPersisted,
   1636                                       const uint64_t aUsage) {
   1637  if (!mGetAll && aQuotaManager->IsOriginInternal(aOrigin)) {
   1638    return;
   1639  }
   1640 
   1641  // We can't store pointers to OriginUsage objects in the hashtable
   1642  // since AppendElement() reallocates its internal array buffer as number
   1643  // of elements grows.
   1644  const auto& originUsage =
   1645      mOriginUsagesIndex.WithEntryHandle(aOrigin, [&](auto&& entry) {
   1646        if (entry) {
   1647          return WrapNotNullUnchecked(&mOriginUsages[entry.Data()]);
   1648        }
   1649 
   1650        entry.Insert(mOriginUsages.Length());
   1651 
   1652        OriginUsageMetadata metadata;
   1653        metadata.mOrigin = aOrigin;
   1654        metadata.mIsPrivate = false;
   1655        metadata.mPersistenceType = PERSISTENCE_TYPE_DEFAULT;
   1656        metadata.mLastAccessTime = 0;
   1657        metadata.mLastMaintenanceDate = 0;
   1658        metadata.mAccessed = false;
   1659        metadata.mPersisted = false;
   1660        metadata.mOriginUsage = 0;
   1661        metadata.mQuotaVersion = kNoQuotaVersion;
   1662        metadata.mUsage = 0;
   1663 
   1664        return mOriginUsages.EmplaceBack(std::move(metadata));
   1665      });
   1666 
   1667  if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) {
   1668    originUsage->mPersisted = aPersisted;
   1669  }
   1670 
   1671  originUsage->mUsage = originUsage->mUsage + aUsage;
   1672 
   1673  originUsage->mLastAccessTime =
   1674      std::max<int64_t>(originUsage->mLastAccessTime, aTimestamp);
   1675 }
   1676 
   1677 const Atomic<bool>& GetUsageOp::GetIsCanceledFlag() {
   1678  AssertIsOnIOThread();
   1679 
   1680  return Canceled();
   1681 }
   1682 
   1683 // XXX Remove aPersistent
   1684 // XXX Remove aPersistenceType once GetUsageForOrigin uses the persistence
   1685 // type from OriginMetadata
   1686 nsresult GetUsageOp::ProcessOrigin(QuotaManager& aQuotaManager,
   1687                                   nsIFile& aOriginDir, const bool aPersistent,
   1688                                   const PersistenceType aPersistenceType) {
   1689  AssertIsOnIOThread();
   1690 
   1691  QM_TRY_UNWRAP(auto maybeMetadata,
   1692                QM_OR_ELSE_WARN_IF(
   1693                    // Expression
   1694                    aQuotaManager.LoadFullOriginMetadataWithRestore(&aOriginDir)
   1695                        .map([](auto metadata) -> Maybe<FullOriginMetadata> {
   1696                          return Some(std::move(metadata));
   1697                        }),
   1698                    // Predicate.
   1699                    IsSpecificError<NS_ERROR_MALFORMED_URI>,
   1700                    // Fallback.
   1701                    ErrToDefaultOk<Maybe<FullOriginMetadata>>));
   1702 
   1703  if (!maybeMetadata) {
   1704    // Unknown directories during getting usage are allowed. Just warn if we
   1705    // find them.
   1706    QM_TRY_INSPECT(const auto& leafName,
   1707                   MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, aOriginDir,
   1708                                                     GetLeafName));
   1709 
   1710    UNKNOWN_FILE_WARNING(leafName);
   1711    return NS_OK;
   1712  }
   1713 
   1714  auto metadata = maybeMetadata.extract();
   1715 
   1716  QM_TRY_INSPECT(const auto& usageInfo,
   1717                 GetUsageForOrigin(aQuotaManager, aPersistenceType, metadata));
   1718 
   1719  ProcessOriginInternal(&aQuotaManager, aPersistenceType, metadata.mOrigin,
   1720                        metadata.mLastAccessTime, metadata.mPersisted,
   1721                        usageInfo.TotalUsage().valueOr(0));
   1722 
   1723  return NS_OK;
   1724 }
   1725 
   1726 RefPtr<BoolPromise> GetUsageOp::OpenDirectory() {
   1727  AssertIsOnOwningThread();
   1728 
   1729  return OpenStorageDirectory(PersistenceScope::CreateFromNull(),
   1730                              OriginScope::FromNull(),
   1731                              ClientStorageScope::CreateFromNull(),
   1732                              /* aExclusive */ false);
   1733 }
   1734 
   1735 nsresult GetUsageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   1736  AssertIsOnIOThread();
   1737  aQuotaManager.AssertStorageIsInitializedInternal();
   1738 
   1739  AUTO_PROFILER_LABEL("GetUsageOp::DoDirectoryWork", OTHER);
   1740 
   1741  nsresult rv;
   1742 
   1743  for (const PersistenceType type : kAllPersistenceTypes) {
   1744    rv = TraverseRepository(aQuotaManager, type);
   1745    if (NS_WARN_IF(NS_FAILED(rv))) {
   1746      return rv;
   1747    }
   1748  }
   1749 
   1750  // TraverseRepository above only consulted the filesystem. We also need to
   1751  // consider origins which may have pending quota usage, such as buffered
   1752  // LocalStorage writes for an origin which didn't previously have any
   1753  // LocalStorage data.
   1754 
   1755  aQuotaManager.CollectPendingOriginsForListing(
   1756      [this, &aQuotaManager](const auto& originInfo) {
   1757        ProcessOriginInternal(
   1758            &aQuotaManager, originInfo->GetGroupInfo()->GetPersistenceType(),
   1759            originInfo->Origin(), originInfo->LockedAccessTime(),
   1760            originInfo->LockedPersisted(), originInfo->LockedUsage());
   1761      });
   1762 
   1763  return NS_OK;
   1764 }
   1765 
   1766 OriginUsageMetadataArray GetUsageOp::UnwrapResolveValue() {
   1767  AssertIsOnOwningThread();
   1768 
   1769  return std::move(mOriginUsages);
   1770 }
   1771 
   1772 void GetUsageOp::CloseDirectory() {
   1773  AssertIsOnOwningThread();
   1774 
   1775  SafeDropDirectoryLock(mDirectoryLock);
   1776 }
   1777 
   1778 GetOriginUsageOp::GetOriginUsageOp(
   1779    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1780    const PrincipalInfo& aPrincipalInfo)
   1781    : OpenStorageDirectoryHelper(std::move(aQuotaManager),
   1782                                 "dom::quota::GetOriginUsageOp"),
   1783      mPrincipalInfo(aPrincipalInfo) {
   1784  AssertIsOnOwningThread();
   1785 }
   1786 
   1787 nsresult GetOriginUsageOp::DoInit(QuotaManager& aQuotaManager) {
   1788  AssertIsOnOwningThread();
   1789 
   1790  QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
   1791                                        aQuotaManager, mPrincipalInfo));
   1792 
   1793  mPrincipalMetadata.AssertInvariants();
   1794 
   1795  return NS_OK;
   1796 }
   1797 
   1798 RefPtr<BoolPromise> GetOriginUsageOp::OpenDirectory() {
   1799  AssertIsOnOwningThread();
   1800 
   1801  return OpenStorageDirectory(PersistenceScope::CreateFromNull(),
   1802                              OriginScope::FromOrigin(mPrincipalMetadata),
   1803                              ClientStorageScope::CreateFromNull(),
   1804                              /* aExclusive */ false);
   1805 }
   1806 
   1807 const Atomic<bool>& GetOriginUsageOp::GetIsCanceledFlag() {
   1808  AssertIsOnIOThread();
   1809 
   1810  return Canceled();
   1811 }
   1812 
   1813 nsresult GetOriginUsageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   1814  AssertIsOnIOThread();
   1815  aQuotaManager.AssertStorageIsInitializedInternal();
   1816  MOZ_ASSERT(mUsageInfo.TotalUsage().isNothing());
   1817 
   1818  AUTO_PROFILER_LABEL("GetOriginUsageOp::DoDirectoryWork", OTHER);
   1819 
   1820  // Add all the persistent/temporary/default/private storage files we care
   1821  // about.
   1822  for (const PersistenceType type : kAllPersistenceTypes) {
   1823    const OriginMetadata originMetadata = {mPrincipalMetadata, type};
   1824 
   1825    auto usageInfoOrErr =
   1826        GetUsageForOrigin(aQuotaManager, type, originMetadata);
   1827    if (NS_WARN_IF(usageInfoOrErr.isErr())) {
   1828      return usageInfoOrErr.unwrapErr();
   1829    }
   1830 
   1831    mUsageInfo += usageInfoOrErr.unwrap();
   1832  }
   1833 
   1834  return NS_OK;
   1835 }
   1836 
   1837 UsageInfo GetOriginUsageOp::UnwrapResolveValue() {
   1838  AssertIsOnOwningThread();
   1839 
   1840  return mUsageInfo;
   1841 }
   1842 
   1843 void GetOriginUsageOp::CloseDirectory() {
   1844  AssertIsOnOwningThread();
   1845 
   1846  SafeDropDirectoryLock(mDirectoryLock);
   1847 }
   1848 
   1849 StorageNameOp::StorageNameOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
   1850    : QuotaRequestBase(std::move(aQuotaManager), "dom::quota::StorageNameOp") {
   1851  AssertIsOnOwningThread();
   1852 }
   1853 
   1854 RefPtr<BoolPromise> StorageNameOp::OpenDirectory() {
   1855  AssertIsOnOwningThread();
   1856 
   1857  return BoolPromise::CreateAndResolve(true, __func__);
   1858 }
   1859 
   1860 nsresult StorageNameOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   1861  AssertIsOnIOThread();
   1862 
   1863  AUTO_PROFILER_LABEL("StorageNameOp::DoDirectoryWork", OTHER);
   1864 
   1865  mName = aQuotaManager.GetStorageName();
   1866 
   1867  return NS_OK;
   1868 }
   1869 
   1870 void StorageNameOp::GetResponse(RequestResponse& aResponse) {
   1871  AssertIsOnOwningThread();
   1872 
   1873  StorageNameResponse storageNameResponse;
   1874 
   1875  storageNameResponse.name() = mName;
   1876 
   1877  aResponse = storageNameResponse;
   1878 }
   1879 
   1880 void StorageNameOp::CloseDirectory() { AssertIsOnOwningThread(); }
   1881 
   1882 InitializedRequestBase::InitializedRequestBase(
   1883    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName)
   1884    : ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
   1885      mInitialized(false) {
   1886  AssertIsOnOwningThread();
   1887 }
   1888 
   1889 RefPtr<BoolPromise> InitializedRequestBase::OpenDirectory() {
   1890  AssertIsOnOwningThread();
   1891 
   1892  return BoolPromise::CreateAndResolve(true, __func__);
   1893 }
   1894 
   1895 void InitializedRequestBase::CloseDirectory() { AssertIsOnOwningThread(); }
   1896 
   1897 nsresult StorageInitializedOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   1898  AssertIsOnIOThread();
   1899 
   1900  AUTO_PROFILER_LABEL("StorageInitializedOp::DoDirectoryWork", OTHER);
   1901 
   1902  mInitialized = aQuotaManager.IsStorageInitializedInternal();
   1903 
   1904  return NS_OK;
   1905 }
   1906 
   1907 bool StorageInitializedOp::UnwrapResolveValue() {
   1908  AssertIsOnOwningThread();
   1909 
   1910  return mInitialized;
   1911 }
   1912 
   1913 nsresult PersistentStorageInitializedOp::DoDirectoryWork(
   1914    QuotaManager& aQuotaManager) {
   1915  AssertIsOnIOThread();
   1916 
   1917  AUTO_PROFILER_LABEL("PersistentStorageInitializedOp::DoDirectoryWork", OTHER);
   1918 
   1919  mInitialized = aQuotaManager.IsPersistentStorageInitializedInternal();
   1920 
   1921  return NS_OK;
   1922 }
   1923 
   1924 bool PersistentStorageInitializedOp::UnwrapResolveValue() {
   1925  AssertIsOnOwningThread();
   1926 
   1927  return mInitialized;
   1928 }
   1929 
   1930 nsresult TemporaryStorageInitializedOp::DoDirectoryWork(
   1931    QuotaManager& aQuotaManager) {
   1932  AssertIsOnIOThread();
   1933 
   1934  AUTO_PROFILER_LABEL("TemporaryStorageInitializedOp::DoDirectoryWork", OTHER);
   1935 
   1936  mInitialized = aQuotaManager.IsTemporaryStorageInitializedInternal();
   1937 
   1938  return NS_OK;
   1939 }
   1940 
   1941 bool TemporaryStorageInitializedOp::UnwrapResolveValue() {
   1942  AssertIsOnOwningThread();
   1943 
   1944  return mInitialized;
   1945 }
   1946 
   1947 TemporaryGroupInitializedOp::TemporaryGroupInitializedOp(
   1948    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   1949    const PrincipalMetadata& aPrincipalMetadata)
   1950    : ResolvableNormalOriginOp(std::move(aQuotaManager),
   1951                               "dom::quota::TemporaryGroupInitializedOp"),
   1952      mPrincipalMetadata(aPrincipalMetadata),
   1953      mInitialized(false) {
   1954  AssertIsOnOwningThread();
   1955 }
   1956 
   1957 RefPtr<BoolPromise> TemporaryGroupInitializedOp::OpenDirectory() {
   1958  AssertIsOnOwningThread();
   1959 
   1960  return BoolPromise::CreateAndResolve(true, __func__);
   1961 }
   1962 
   1963 nsresult TemporaryGroupInitializedOp::DoDirectoryWork(
   1964    QuotaManager& aQuotaManager) {
   1965  AssertIsOnIOThread();
   1966 
   1967  AUTO_PROFILER_LABEL("TemporaryGroupInitializedOp::DoDirectoryWork", OTHER);
   1968 
   1969  mInitialized =
   1970      aQuotaManager.IsTemporaryGroupInitializedInternal(mPrincipalMetadata);
   1971 
   1972  return NS_OK;
   1973 }
   1974 
   1975 bool TemporaryGroupInitializedOp::UnwrapResolveValue() {
   1976  AssertIsOnOwningThread();
   1977 
   1978  return mInitialized;
   1979 }
   1980 
   1981 void TemporaryGroupInitializedOp::CloseDirectory() { AssertIsOnOwningThread(); }
   1982 
   1983 InitializedOriginRequestBase::InitializedOriginRequestBase(
   1984    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
   1985    const PrincipalMetadata& aPrincipalMetadata)
   1986    : ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
   1987      mPrincipalMetadata(aPrincipalMetadata),
   1988      mInitialized(false) {
   1989  AssertIsOnOwningThread();
   1990 }
   1991 
   1992 RefPtr<BoolPromise> InitializedOriginRequestBase::OpenDirectory() {
   1993  AssertIsOnOwningThread();
   1994 
   1995  return BoolPromise::CreateAndResolve(true, __func__);
   1996 }
   1997 
   1998 void InitializedOriginRequestBase::CloseDirectory() {
   1999  AssertIsOnOwningThread();
   2000 }
   2001 
   2002 PersistentOriginInitializedOp::PersistentOriginInitializedOp(
   2003    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   2004    const OriginMetadata& aOriginMetadata)
   2005    : InitializedOriginRequestBase(std::move(aQuotaManager),
   2006                                   "dom::quota::PersistentOriginInitializedOp",
   2007                                   aOriginMetadata) {
   2008  AssertIsOnOwningThread();
   2009  MOZ_ASSERT(aOriginMetadata.mPersistenceType == PERSISTENCE_TYPE_PERSISTENT);
   2010 }
   2011 
   2012 nsresult PersistentOriginInitializedOp::DoDirectoryWork(
   2013    QuotaManager& aQuotaManager) {
   2014  AssertIsOnIOThread();
   2015 
   2016  AUTO_PROFILER_LABEL("PersistentOriginInitializedOp::DoDirectoryWork", OTHER);
   2017 
   2018  mInitialized = aQuotaManager.IsPersistentOriginInitializedInternal(
   2019      OriginMetadata{mPrincipalMetadata, PERSISTENCE_TYPE_PERSISTENT});
   2020 
   2021  return NS_OK;
   2022 }
   2023 
   2024 bool PersistentOriginInitializedOp::UnwrapResolveValue() {
   2025  AssertIsOnOwningThread();
   2026 
   2027  return mInitialized;
   2028 }
   2029 
   2030 TemporaryOriginInitializedOp::TemporaryOriginInitializedOp(
   2031    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   2032    const OriginMetadata& aOriginMetadata)
   2033    : InitializedOriginRequestBase(std::move(aQuotaManager),
   2034                                   "dom::quota::TemporaryOriginInitializedOp",
   2035                                   aOriginMetadata),
   2036      mPersistenceType(aOriginMetadata.mPersistenceType) {
   2037  AssertIsOnOwningThread();
   2038  MOZ_ASSERT(aOriginMetadata.mPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
   2039 }
   2040 
   2041 nsresult TemporaryOriginInitializedOp::DoDirectoryWork(
   2042    QuotaManager& aQuotaManager) {
   2043  AssertIsOnIOThread();
   2044 
   2045  AUTO_PROFILER_LABEL("TemporaryOriginInitializedOp::DoDirectoryWork", OTHER);
   2046 
   2047  mInitialized = aQuotaManager.IsTemporaryOriginInitializedInternal(
   2048      OriginMetadata{mPrincipalMetadata, mPersistenceType});
   2049 
   2050  return NS_OK;
   2051 }
   2052 
   2053 bool TemporaryOriginInitializedOp::UnwrapResolveValue() {
   2054  AssertIsOnOwningThread();
   2055 
   2056  return mInitialized;
   2057 }
   2058 
   2059 InitOp::InitOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   2060               RefPtr<UniversalDirectoryLock> aDirectoryLock)
   2061    : ResolvableNormalOriginOp(std::move(aQuotaManager), "dom::quota::InitOp"),
   2062      mDirectoryLock(std::move(aDirectoryLock)) {
   2063  AssertIsOnOwningThread();
   2064  MOZ_ASSERT(mDirectoryLock);
   2065 }
   2066 
   2067 RefPtr<BoolPromise> InitOp::OpenDirectory() {
   2068  AssertIsOnOwningThread();
   2069  MOZ_ASSERT(mDirectoryLock);
   2070 
   2071  return BoolPromise::CreateAndResolve(true, __func__);
   2072 }
   2073 
   2074 nsresult InitOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   2075  AssertIsOnIOThread();
   2076 
   2077  AUTO_PROFILER_LABEL("InitOp::DoDirectoryWork", OTHER);
   2078 
   2079  QM_TRY(MOZ_TO_RESULT(aQuotaManager.EnsureStorageIsInitializedInternal()));
   2080 
   2081  return NS_OK;
   2082 }
   2083 
   2084 bool InitOp::UnwrapResolveValue() { return true; }
   2085 
   2086 void InitOp::CloseDirectory() {
   2087  AssertIsOnOwningThread();
   2088 
   2089  DropDirectoryLock(mDirectoryLock);
   2090 }
   2091 
   2092 InitializePersistentStorageOp::InitializePersistentStorageOp(
   2093    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   2094    RefPtr<UniversalDirectoryLock> aDirectoryLock)
   2095    : ResolvableNormalOriginOp(std::move(aQuotaManager),
   2096                               "dom::quota::InitializePersistentStorageOp"),
   2097      mDirectoryLock(std::move(aDirectoryLock)) {
   2098  AssertIsOnOwningThread();
   2099 }
   2100 
   2101 RefPtr<BoolPromise> InitializePersistentStorageOp::OpenDirectory() {
   2102  AssertIsOnOwningThread();
   2103  MOZ_ASSERT(mDirectoryLock);
   2104 
   2105  return BoolPromise::CreateAndResolve(true, __func__);
   2106 }
   2107 
   2108 nsresult InitializePersistentStorageOp::DoDirectoryWork(
   2109    QuotaManager& aQuotaManager) {
   2110  AssertIsOnIOThread();
   2111 
   2112  AUTO_PROFILER_LABEL("InitializePersistentStorageOp::DoDirectoryWork", OTHER);
   2113 
   2114  QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
   2115         NS_ERROR_NOT_INITIALIZED);
   2116 
   2117  QM_TRY(MOZ_TO_RESULT(
   2118      aQuotaManager.EnsurePersistentStorageIsInitializedInternal()));
   2119 
   2120  return NS_OK;
   2121 }
   2122 
   2123 bool InitializePersistentStorageOp::UnwrapResolveValue() {
   2124  AssertIsOnOwningThread();
   2125 
   2126  return true;
   2127 }
   2128 
   2129 void InitializePersistentStorageOp::CloseDirectory() {
   2130  AssertIsOnOwningThread();
   2131 
   2132  DropDirectoryLock(mDirectoryLock);
   2133 }
   2134 
   2135 InitTemporaryStorageOp::InitTemporaryStorageOp(
   2136    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   2137    RefPtr<UniversalDirectoryLock> aDirectoryLock)
   2138    : ResolvableNormalOriginOp(std::move(aQuotaManager),
   2139                               "dom::quota::InitTemporaryStorageOp"),
   2140      mDirectoryLock(std::move(aDirectoryLock)) {
   2141  AssertIsOnOwningThread();
   2142 }
   2143 
   2144 RefPtr<BoolPromise> InitTemporaryStorageOp::OpenDirectory() {
   2145  AssertIsOnOwningThread();
   2146  MOZ_ASSERT(mDirectoryLock);
   2147 
   2148  return BoolPromise::CreateAndResolve(true, __func__);
   2149 }
   2150 
   2151 nsresult InitTemporaryStorageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   2152  AssertIsOnIOThread();
   2153 
   2154  AUTO_PROFILER_LABEL("InitTemporaryStorageOp::DoDirectoryWork", OTHER);
   2155 
   2156  QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
   2157         NS_ERROR_NOT_INITIALIZED);
   2158 
   2159  const bool wasInitialized =
   2160      aQuotaManager.IsTemporaryStorageInitializedInternal();
   2161 
   2162  if (!wasInitialized) {
   2163    QM_TRY(MOZ_TO_RESULT(
   2164        aQuotaManager.EnsureTemporaryStorageIsInitializedInternal()));
   2165 
   2166    mAllTemporaryGroups = Some(aQuotaManager.GetAllTemporaryGroups());
   2167  }
   2168 
   2169  return NS_OK;
   2170 }
   2171 
   2172 MaybePrincipalMetadataArray InitTemporaryStorageOp::UnwrapResolveValue() {
   2173  AssertIsOnOwningThread();
   2174 
   2175  return std::move(mAllTemporaryGroups);
   2176 }
   2177 
   2178 void InitTemporaryStorageOp::CloseDirectory() {
   2179  AssertIsOnOwningThread();
   2180 
   2181  DropDirectoryLock(mDirectoryLock);
   2182 }
   2183 
   2184 InitializeTemporaryGroupOp::InitializeTemporaryGroupOp(
   2185    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   2186    const PrincipalMetadata& aPrincipalMetadata,
   2187    RefPtr<UniversalDirectoryLock> aDirectoryLock)
   2188    : ResolvableNormalOriginOp(std::move(aQuotaManager),
   2189                               "dom::quota::InitializeTemporaryGroupOp"),
   2190      mPrincipalMetadata(aPrincipalMetadata),
   2191      mDirectoryLock(std::move(aDirectoryLock)) {
   2192  AssertIsOnOwningThread();
   2193 }
   2194 
   2195 RefPtr<BoolPromise> InitializeTemporaryGroupOp::OpenDirectory() {
   2196  AssertIsOnOwningThread();
   2197  MOZ_ASSERT(mDirectoryLock);
   2198 
   2199  return BoolPromise::CreateAndResolve(true, __func__);
   2200 }
   2201 
   2202 nsresult InitializeTemporaryGroupOp::DoDirectoryWork(
   2203    QuotaManager& aQuotaManager) {
   2204  AssertIsOnIOThread();
   2205 
   2206  AUTO_PROFILER_LABEL("InitializeTemporaryGroupOp::DoDirectoryWork", OTHER);
   2207 
   2208  QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
   2209         NS_ERROR_NOT_INITIALIZED);
   2210 
   2211  QM_TRY(OkIf(aQuotaManager.IsTemporaryStorageInitializedInternal()),
   2212         NS_ERROR_NOT_INITIALIZED);
   2213 
   2214  QM_TRY(aQuotaManager.EnsureTemporaryGroupIsInitializedInternal(
   2215      mPrincipalMetadata));
   2216 
   2217  return NS_OK;
   2218 }
   2219 
   2220 bool InitializeTemporaryGroupOp::UnwrapResolveValue() {
   2221  AssertIsOnOwningThread();
   2222 
   2223  return true;
   2224 }
   2225 
   2226 void InitializeTemporaryGroupOp::CloseDirectory() {
   2227  AssertIsOnOwningThread();
   2228 
   2229  DropDirectoryLock(mDirectoryLock);
   2230 }
   2231 
   2232 InitializeOriginRequestBase::InitializeOriginRequestBase(
   2233    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
   2234    const PrincipalMetadata& aPrincipalMetadata,
   2235    RefPtr<UniversalDirectoryLock> aDirectoryLock)
   2236    : ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
   2237      mPrincipalMetadata(aPrincipalMetadata),
   2238      mDirectoryLock(std::move(aDirectoryLock)),
   2239      mCreated(false) {
   2240  AssertIsOnOwningThread();
   2241 }
   2242 
   2243 RefPtr<BoolPromise> InitializeOriginRequestBase::OpenDirectory() {
   2244  AssertIsOnOwningThread();
   2245  MOZ_ASSERT(mDirectoryLock);
   2246 
   2247  return BoolPromise::CreateAndResolve(true, __func__);
   2248 }
   2249 
   2250 void InitializeOriginRequestBase::CloseDirectory() {
   2251  AssertIsOnOwningThread();
   2252 
   2253  DropDirectoryLockIfNotDropped(mDirectoryLock);
   2254 }
   2255 
   2256 InitializePersistentOriginOp::InitializePersistentOriginOp(
   2257    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   2258    const OriginMetadata& aOriginMetadata,
   2259    RefPtr<UniversalDirectoryLock> aDirectoryLock)
   2260    : InitializeOriginRequestBase(std::move(aQuotaManager),
   2261                                  "dom::quota::InitializePersistentOriginOp",
   2262                                  aOriginMetadata, std::move(aDirectoryLock)) {
   2263  AssertIsOnOwningThread();
   2264  MOZ_ASSERT(aOriginMetadata.mPersistenceType == PERSISTENCE_TYPE_PERSISTENT);
   2265 }
   2266 
   2267 nsresult InitializePersistentOriginOp::DoDirectoryWork(
   2268    QuotaManager& aQuotaManager) {
   2269  AssertIsOnIOThread();
   2270 
   2271  AUTO_PROFILER_LABEL("InitializePersistentOriginOp::DoDirectoryWork", OTHER);
   2272 
   2273  QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
   2274         NS_ERROR_NOT_INITIALIZED);
   2275 
   2276  QM_TRY_UNWRAP(
   2277      mCreated,
   2278      (aQuotaManager
   2279           .EnsurePersistentOriginIsInitializedInternal(
   2280               OriginMetadata{mPrincipalMetadata, PERSISTENCE_TYPE_PERSISTENT})
   2281           .map([](const auto& res) { return res.second; })));
   2282 
   2283  return NS_OK;
   2284 }
   2285 
   2286 bool InitializePersistentOriginOp::UnwrapResolveValue() {
   2287  AssertIsOnOwningThread();
   2288 
   2289  return mCreated;
   2290 }
   2291 
   2292 InitializeTemporaryOriginOp::InitializeTemporaryOriginOp(
   2293    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   2294    const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent,
   2295    RefPtr<UniversalDirectoryLock> aDirectoryLock)
   2296    : InitializeOriginRequestBase(std::move(aQuotaManager),
   2297                                  "dom::quota::InitializeTemporaryOriginOp",
   2298                                  aOriginMetadata, std::move(aDirectoryLock)),
   2299      mPersistenceType(aOriginMetadata.mPersistenceType),
   2300      mCreateIfNonExistent(aCreateIfNonExistent) {
   2301  AssertIsOnOwningThread();
   2302  MOZ_ASSERT(aOriginMetadata.mPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
   2303 }
   2304 
   2305 nsresult InitializeTemporaryOriginOp::DoDirectoryWork(
   2306    QuotaManager& aQuotaManager) {
   2307  AssertIsOnIOThread();
   2308 
   2309  AUTO_PROFILER_LABEL("InitializeTemporaryOriginOp::DoDirectoryWork", OTHER);
   2310 
   2311  QM_TRY(OkIf(aQuotaManager.IsStorageInitializedInternal()),
   2312         NS_ERROR_NOT_INITIALIZED);
   2313 
   2314  QM_TRY(OkIf(aQuotaManager.IsTemporaryStorageInitializedInternal()),
   2315         NS_ERROR_NOT_INITIALIZED);
   2316 
   2317  QM_TRY_UNWRAP(mCreated,
   2318                (aQuotaManager
   2319                     .EnsureTemporaryOriginIsInitializedInternal(
   2320                         OriginMetadata{mPrincipalMetadata, mPersistenceType},
   2321                         mCreateIfNonExistent)
   2322                     .map([](const auto& res) { return res.second; })));
   2323 
   2324  return NS_OK;
   2325 }
   2326 
   2327 bool InitializeTemporaryOriginOp::UnwrapResolveValue() {
   2328  AssertIsOnOwningThread();
   2329 
   2330  return mCreated;
   2331 }
   2332 
   2333 InitializeClientBase::InitializeClientBase(
   2334    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager, const char* aName,
   2335    const ClientMetadata& aClientMetadata,
   2336    RefPtr<UniversalDirectoryLock> aDirectoryLock)
   2337    : ResolvableNormalOriginOp(std::move(aQuotaManager), aName),
   2338      mClientMetadata(aClientMetadata),
   2339      mDirectoryLock(std::move(aDirectoryLock)),
   2340      mCreated(false) {
   2341  AssertIsOnOwningThread();
   2342 }
   2343 
   2344 RefPtr<BoolPromise> InitializeClientBase::OpenDirectory() {
   2345  AssertIsOnOwningThread();
   2346  MOZ_ASSERT(mDirectoryLock);
   2347 
   2348  return BoolPromise::CreateAndResolve(true, __func__);
   2349 }
   2350 
   2351 void InitializeClientBase::CloseDirectory() {
   2352  AssertIsOnOwningThread();
   2353 
   2354  DropDirectoryLockIfNotDropped(mDirectoryLock);
   2355 }
   2356 
   2357 InitializePersistentClientOp::InitializePersistentClientOp(
   2358    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   2359    const ClientMetadata& aClientMetadata,
   2360    RefPtr<UniversalDirectoryLock> aDirectoryLock)
   2361    : InitializeClientBase(std::move(aQuotaManager),
   2362                           "dom::quota::InitializePersistentClientOp",
   2363                           aClientMetadata, std::move(aDirectoryLock)) {
   2364  AssertIsOnOwningThread();
   2365 }
   2366 
   2367 nsresult InitializePersistentClientOp::DoDirectoryWork(
   2368    QuotaManager& aQuotaManager) {
   2369  AssertIsOnIOThread();
   2370 
   2371  AUTO_PROFILER_LABEL("InitializePersistentClientOp::DoDirectoryWork", OTHER);
   2372 
   2373  QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsStorageInitializedInternal()),
   2374         NS_ERROR_FAILURE);
   2375 
   2376  QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsPersistentOriginInitializedInternal(
   2377             mClientMetadata)),
   2378         NS_ERROR_FAILURE);
   2379 
   2380  QM_TRY_UNWRAP(
   2381      mCreated,
   2382      (aQuotaManager.EnsurePersistentClientIsInitialized(mClientMetadata)
   2383           .map([](const auto& res) { return res.second; })));
   2384 
   2385  return NS_OK;
   2386 }
   2387 
   2388 bool InitializePersistentClientOp::UnwrapResolveValue() {
   2389  AssertIsOnOwningThread();
   2390 
   2391  return mCreated;
   2392 }
   2393 
   2394 InitializeTemporaryClientOp::InitializeTemporaryClientOp(
   2395    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   2396    const ClientMetadata& aClientMetadata, bool aCreateIfNonExistent,
   2397    RefPtr<UniversalDirectoryLock> aDirectoryLock)
   2398    : InitializeClientBase(std::move(aQuotaManager),
   2399                           "dom::quota::InitializeTemporaryClientOp",
   2400                           aClientMetadata, std::move(aDirectoryLock)),
   2401      mCreateIfNonExistent(aCreateIfNonExistent) {
   2402  AssertIsOnOwningThread();
   2403 }
   2404 
   2405 nsresult InitializeTemporaryClientOp::DoDirectoryWork(
   2406    QuotaManager& aQuotaManager) {
   2407  AssertIsOnIOThread();
   2408 
   2409  AUTO_PROFILER_LABEL("InitializeTemporaryClientOp::DoDirectoryWork", OTHER);
   2410 
   2411  QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsStorageInitializedInternal()),
   2412         NS_ERROR_FAILURE);
   2413 
   2414  QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsTemporaryStorageInitializedInternal()),
   2415         NS_ERROR_FAILURE);
   2416 
   2417  // Return a special error code so the caller (or QM_TRY logging) can treat it
   2418  // as a non-critical, expected case. Due to optimizations like LSNG datastore
   2419  // preloading, temporary client initialization may be attempted before the
   2420  // corresponding temporary origin has been initialized. In such cases, it's
   2421  // not an actual error, it's used to signal early that there's nothing to
   2422  // preload.
   2423  QM_TRY(MOZ_TO_RESULT(aQuotaManager.IsTemporaryOriginInitializedInternal(
   2424                           mClientMetadata))
   2425             .mapErr([](const nsresult) {
   2426               return NS_ERROR_DOM_QM_CLIENT_INIT_ORIGIN_UNINITIALIZED;
   2427             }));
   2428 
   2429  QM_TRY_UNWRAP(mCreated,
   2430                (aQuotaManager
   2431                     .EnsureTemporaryClientIsInitialized(mClientMetadata,
   2432                                                         mCreateIfNonExistent)
   2433                     .map([](const auto& res) { return res.second; })));
   2434 
   2435  return NS_OK;
   2436 }
   2437 
   2438 bool InitializeTemporaryClientOp::UnwrapResolveValue() {
   2439  AssertIsOnOwningThread();
   2440 
   2441  return mCreated;
   2442 }
   2443 
   2444 GetFullOriginMetadataOp::GetFullOriginMetadataOp(
   2445    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   2446    const GetFullOriginMetadataParams& aParams)
   2447    : OpenStorageDirectoryHelper(std::move(aQuotaManager),
   2448                                 "dom::quota::GetFullOriginMetadataOp"),
   2449      mParams(aParams) {
   2450  AssertIsOnOwningThread();
   2451 }
   2452 
   2453 nsresult GetFullOriginMetadataOp::DoInit(QuotaManager& aQuotaManager) {
   2454  AssertIsOnOwningThread();
   2455 
   2456  QM_TRY_UNWRAP(PrincipalMetadata principalMetadata,
   2457                GetInfoFromValidatedPrincipalInfo(aQuotaManager,
   2458                                                  mParams.principalInfo()));
   2459 
   2460  principalMetadata.AssertInvariants();
   2461 
   2462  mOriginMetadata = {std::move(principalMetadata), mParams.persistenceType()};
   2463 
   2464  return NS_OK;
   2465 }
   2466 
   2467 RefPtr<BoolPromise> GetFullOriginMetadataOp::OpenDirectory() {
   2468  AssertIsOnOwningThread();
   2469 
   2470  return OpenStorageDirectory(
   2471      PersistenceScope::CreateFromValue(mOriginMetadata.mPersistenceType),
   2472      OriginScope::FromOrigin(mOriginMetadata),
   2473      ClientStorageScope::CreateFromNull(),
   2474      /* aExclusive */ false,
   2475      /* aInitializeOrigins */ true);
   2476 }
   2477 
   2478 nsresult GetFullOriginMetadataOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   2479  AssertIsOnIOThread();
   2480  aQuotaManager.AssertStorageIsInitializedInternal();
   2481 
   2482  AUTO_PROFILER_LABEL("GetFullOriginMetadataOp::DoDirectoryWork", OTHER);
   2483 
   2484  // Get metadata cached in memory (the method doesn't have to stat any
   2485  // files).
   2486  mMaybeFullOriginMetadata =
   2487      aQuotaManager.GetFullOriginMetadata(mOriginMetadata);
   2488 
   2489  return NS_OK;
   2490 }
   2491 
   2492 void GetFullOriginMetadataOp::GetResponse(RequestResponse& aResponse) {
   2493  AssertIsOnOwningThread();
   2494 
   2495  aResponse = GetFullOriginMetadataResponse();
   2496  aResponse.get_GetFullOriginMetadataResponse().maybeFullOriginMetadata() =
   2497      std::move(mMaybeFullOriginMetadata);
   2498 }
   2499 
   2500 void GetFullOriginMetadataOp::CloseDirectory() {
   2501  AssertIsOnOwningThread();
   2502 
   2503  SafeDropDirectoryLock(mDirectoryLock);
   2504 }
   2505 
   2506 GetCachedOriginUsageOp::GetCachedOriginUsageOp(
   2507    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   2508    const PrincipalInfo& aPrincipalInfo)
   2509    : OpenStorageDirectoryHelper(std::move(aQuotaManager),
   2510                                 "dom::quota::GetCachedOriginUsageOp"),
   2511      mPrincipalInfo(aPrincipalInfo),
   2512      mUsage(0) {
   2513  AssertIsOnOwningThread();
   2514 }
   2515 
   2516 nsresult GetCachedOriginUsageOp::DoInit(QuotaManager& aQuotaManager) {
   2517  AssertIsOnOwningThread();
   2518 
   2519  QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
   2520                                        aQuotaManager, mPrincipalInfo));
   2521 
   2522  mPrincipalMetadata.AssertInvariants();
   2523 
   2524  return NS_OK;
   2525 }
   2526 
   2527 RefPtr<BoolPromise> GetCachedOriginUsageOp::OpenDirectory() {
   2528  AssertIsOnOwningThread();
   2529 
   2530  return OpenStorageDirectory(
   2531      PersistenceScope::CreateFromSet(PERSISTENCE_TYPE_TEMPORARY,
   2532                                      PERSISTENCE_TYPE_DEFAULT,
   2533                                      PERSISTENCE_TYPE_PRIVATE),
   2534      OriginScope::FromOrigin(mPrincipalMetadata),
   2535      ClientStorageScope::CreateFromNull(),
   2536      /* aExclusive */ false);
   2537 }
   2538 
   2539 nsresult GetCachedOriginUsageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   2540  AssertIsOnIOThread();
   2541  MOZ_ASSERT(mUsage == 0);
   2542 
   2543  AUTO_PROFILER_LABEL("GetCachedOriginUsageOp::DoDirectoryWork", OTHER);
   2544 
   2545  // If temporary storage hasn't been initialized yet, there's no cached usage
   2546  // to report.
   2547  if (!aQuotaManager.IsTemporaryStorageInitializedInternal()) {
   2548    return NS_OK;
   2549  }
   2550 
   2551  // Get cached usage (the method doesn't have to stat any files).
   2552  mUsage = aQuotaManager.GetOriginUsage(mPrincipalMetadata);
   2553 
   2554  return NS_OK;
   2555 }
   2556 
   2557 uint64_t GetCachedOriginUsageOp::UnwrapResolveValue() {
   2558  AssertIsOnOwningThread();
   2559 
   2560  return mUsage;
   2561 }
   2562 
   2563 void GetCachedOriginUsageOp::CloseDirectory() {
   2564  AssertIsOnOwningThread();
   2565 
   2566  SafeDropDirectoryLock(mDirectoryLock);
   2567 }
   2568 
   2569 ListCachedOriginsOp::ListCachedOriginsOp(
   2570    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
   2571    : OpenStorageDirectoryHelper(std::move(aQuotaManager),
   2572                                 "dom::quota::ListCachedOriginsOp") {
   2573  AssertIsOnOwningThread();
   2574 }
   2575 
   2576 RefPtr<BoolPromise> ListCachedOriginsOp::OpenDirectory() {
   2577  AssertIsOnOwningThread();
   2578 
   2579  return OpenStorageDirectory(PersistenceScope::CreateFromNull(),
   2580                              OriginScope::FromNull(),
   2581                              ClientStorageScope::CreateFromNull(),
   2582                              /* aExclusive */ false);
   2583 }
   2584 
   2585 nsresult ListCachedOriginsOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   2586  AssertIsOnIOThread();
   2587  MOZ_ASSERT(mOrigins.Length() == 0);
   2588 
   2589  AUTO_PROFILER_LABEL("ListCachedOriginsOp::DoDirectoryWork", OTHER);
   2590 
   2591  // If temporary storage hasn't been initialized yet, there are no cached
   2592  // origins to report.
   2593  if (!aQuotaManager.IsTemporaryStorageInitializedInternal()) {
   2594    return NS_OK;
   2595  }
   2596 
   2597  // Get cached origins (the method doesn't have to stat any files).
   2598  OriginMetadataArray originMetadataArray =
   2599      aQuotaManager.GetAllTemporaryOrigins();
   2600 
   2601  std::transform(originMetadataArray.cbegin(), originMetadataArray.cend(),
   2602                 MakeBackInserter(mOrigins), [](const auto& originMetadata) {
   2603                   return originMetadata.mOrigin;
   2604                 });
   2605 
   2606  return NS_OK;
   2607 }
   2608 
   2609 CStringArray ListCachedOriginsOp::UnwrapResolveValue() {
   2610  AssertIsOnOwningThread();
   2611  MOZ_ASSERT(!ResolveValueConsumed());
   2612 
   2613  return std::move(mOrigins);
   2614 }
   2615 
   2616 void ListCachedOriginsOp::CloseDirectory() {
   2617  AssertIsOnOwningThread();
   2618 
   2619  SafeDropDirectoryLock(mDirectoryLock);
   2620 }
   2621 
   2622 ClearStorageOp::ClearStorageOp(
   2623    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
   2624    : OpenStorageDirectoryHelper(std::move(aQuotaManager),
   2625                                 "dom::quota::ClearStorageOp") {
   2626  AssertIsOnOwningThread();
   2627 }
   2628 
   2629 void ClearStorageOp::DeleteFiles(QuotaManager& aQuotaManager) {
   2630  AssertIsOnIOThread();
   2631 
   2632  nsresult rv = aQuotaManager.AboutToClearOrigins(
   2633      PersistenceScope::CreateFromNull(), OriginScope::FromNull(),
   2634      ClientStorageScope::CreateFromNull());
   2635  if (NS_WARN_IF(NS_FAILED(rv))) {
   2636    return;
   2637  }
   2638 
   2639  auto directoryOrErr = QM_NewLocalFile(aQuotaManager.GetStoragePath());
   2640  if (NS_WARN_IF(directoryOrErr.isErr())) {
   2641    return;
   2642  }
   2643 
   2644  nsCOMPtr<nsIFile> directory = directoryOrErr.unwrap();
   2645 
   2646  rv = directory->Remove(true);
   2647  if (rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
   2648    // This should never fail if we've closed all storage connections
   2649    // correctly...
   2650    MOZ_ASSERT(false, "Failed to remove storage directory!");
   2651  }
   2652 }
   2653 
   2654 void ClearStorageOp::DeleteStorageFile(QuotaManager& aQuotaManager) {
   2655  AssertIsOnIOThread();
   2656 
   2657  QM_TRY_INSPECT(const auto& storageFile,
   2658                 QM_NewLocalFile(aQuotaManager.GetBasePath()), QM_VOID);
   2659 
   2660  QM_TRY(MOZ_TO_RESULT(storageFile->Append(aQuotaManager.GetStorageName() +
   2661                                           kSQLiteSuffix)),
   2662         QM_VOID);
   2663 
   2664  const nsresult rv = storageFile->Remove(true);
   2665  if (rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
   2666    // This should never fail if we've closed the storage connection
   2667    // correctly...
   2668    MOZ_ASSERT(false, "Failed to remove storage file!");
   2669  }
   2670 }
   2671 
   2672 RefPtr<BoolPromise> ClearStorageOp::OpenDirectory() {
   2673  AssertIsOnOwningThread();
   2674 
   2675  return OpenStorageDirectory(
   2676      PersistenceScope::CreateFromNull(), OriginScope::FromNull(),
   2677      ClientStorageScope::CreateFromNull(),
   2678      /* aExclusive */ true,
   2679      /* aInitializeOrigins */ false, DirectoryLockCategory::UninitStorage);
   2680 }
   2681 
   2682 nsresult ClearStorageOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   2683  AssertIsOnIOThread();
   2684  aQuotaManager.AssertStorageIsInitializedInternal();
   2685 
   2686  AUTO_PROFILER_LABEL("ClearStorageOp::DoDirectoryWork", OTHER);
   2687 
   2688  DeleteFiles(aQuotaManager);
   2689 
   2690  aQuotaManager.RemoveQuota();
   2691 
   2692  aQuotaManager.ShutdownStorageInternal();
   2693 
   2694  DeleteStorageFile(aQuotaManager);
   2695 
   2696  return NS_OK;
   2697 }
   2698 
   2699 bool ClearStorageOp::UnwrapResolveValue() {
   2700  AssertIsOnOwningThread();
   2701 
   2702  return true;
   2703 }
   2704 
   2705 void ClearStorageOp::CloseDirectory() {
   2706  AssertIsOnOwningThread();
   2707 
   2708  SafeDropDirectoryLock(mDirectoryLock);
   2709 }
   2710 
   2711 void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
   2712                                   const OriginMetadata& aOriginMetadata) {
   2713  AssertIsOnIOThread();
   2714 
   2715  DeleteFilesInternal(
   2716      aQuotaManager, aOriginMetadata.mPersistenceType,
   2717      OriginScope::FromOrigin(aOriginMetadata),
   2718      [&aQuotaManager, &aOriginMetadata](
   2719          const std::function<Result<Ok, nsresult>(nsCOMPtr<nsIFile>)>& aBody)
   2720          -> Result<Ok, nsresult> {
   2721        QM_TRY_UNWRAP(auto directory,
   2722                      aQuotaManager.GetOriginDirectory(aOriginMetadata));
   2723 
   2724        // We're not checking if the origin directory actualy exists because
   2725        // it can be a pending origin (OriginInfo does exist but the origin
   2726        // directory hasn't been created yet).
   2727 
   2728        QM_TRY_RETURN(aBody(std::move(directory)));
   2729      });
   2730 }
   2731 
   2732 void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
   2733                                   PersistenceType aPersistenceType,
   2734                                   const OriginScope& aOriginScope) {
   2735  AssertIsOnIOThread();
   2736 
   2737  DeleteFilesInternal(
   2738      aQuotaManager, aPersistenceType, aOriginScope,
   2739      [&aQuotaManager, &aPersistenceType](
   2740          const std::function<Result<Ok, nsresult>(nsCOMPtr<nsIFile>)>& aBody)
   2741          -> Result<Ok, nsresult> {
   2742        QM_TRY_INSPECT(
   2743            const auto& directory,
   2744            QM_NewLocalFile(aQuotaManager.GetStoragePath(aPersistenceType)));
   2745 
   2746        QM_TRY_INSPECT(const bool& exists,
   2747                       MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
   2748 
   2749        if (!exists) {
   2750          return Ok{};
   2751        }
   2752 
   2753        QM_TRY(CollectEachFile(*directory, aBody));
   2754 
   2755        // CollectEachFile above only consulted the file-system to get a list of
   2756        // known origins, but we also need to include origins that have pending
   2757        // quota usage.
   2758 
   2759        nsTArray<OriginMetadata> originMetadataArray;
   2760        aQuotaManager.CollectPendingOriginsForListing(
   2761            [aPersistenceType, &originMetadataArray](const auto& originInfo) {
   2762              if (originInfo->GetGroupInfo()->GetPersistenceType() !=
   2763                  aPersistenceType) {
   2764                return;
   2765              }
   2766              originMetadataArray.AppendElement(
   2767                  originInfo->FlattenToOriginMetadata());
   2768            });
   2769 
   2770        if (originMetadataArray.IsEmpty()) {
   2771          return Ok{};
   2772        }
   2773 
   2774        nsTArray<nsCOMPtr<nsIFile>> originDirectories;
   2775        QM_TRY(TransformAbortOnErr(
   2776            originMetadataArray, MakeBackInserter(originDirectories),
   2777            [&aQuotaManager](const auto& originMetadata)
   2778                -> Result<nsCOMPtr<nsIFile>, nsresult> {
   2779              QM_TRY_UNWRAP(auto originDirectory,
   2780                            aQuotaManager.GetOriginDirectory(originMetadata));
   2781              return originDirectory;
   2782            }));
   2783 
   2784        QM_TRY_RETURN(CollectEachInRange(originDirectories, aBody));
   2785      });
   2786 }
   2787 
   2788 template <typename FileCollector>
   2789 void ClearRequestBase::DeleteFilesInternal(
   2790    QuotaManager& aQuotaManager, PersistenceType aPersistenceType,
   2791    const OriginScope& aOriginScope, const FileCollector& aFileCollector) {
   2792  AssertIsOnIOThread();
   2793 
   2794  QM_TRY(MOZ_TO_RESULT(aQuotaManager.AboutToClearOrigins(
   2795             PersistenceScope::CreateFromValue(aPersistenceType), aOriginScope,
   2796             ClientStorageScope::CreateFromNull())),
   2797         QM_VOID);
   2798 
   2799  nsTArray<nsCOMPtr<nsIFile>> directoriesForRemovalRetry;
   2800 
   2801  aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
   2802      "ClearRequestBase: Starting deleting files"_ns);
   2803 
   2804  QM_TRY(
   2805      aFileCollector([&originScope = aOriginScope, aPersistenceType,
   2806                      &aQuotaManager, &directoriesForRemovalRetry,
   2807                      this](nsCOMPtr<nsIFile> file)
   2808                         -> mozilla::Result<Ok, nsresult> {
   2809        QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*file));
   2810 
   2811        QM_TRY_INSPECT(
   2812            const auto& leafName,
   2813            MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, file, GetLeafName));
   2814 
   2815        switch (dirEntryKind) {
   2816          case nsIFileKind::ExistsAsDirectory: {
   2817            QM_TRY_UNWRAP(auto maybeMetadata,
   2818                          QM_OR_ELSE_WARN_IF(
   2819                              // Expression
   2820                              aQuotaManager.GetOriginMetadata(file).map(
   2821                                  [](auto metadata) -> Maybe<OriginMetadata> {
   2822                                    return Some(std::move(metadata));
   2823                                  }),
   2824                              // Predicate.
   2825                              IsSpecificError<NS_ERROR_MALFORMED_URI>,
   2826                              // Fallback.
   2827                              ErrToDefaultOk<Maybe<OriginMetadata>>));
   2828 
   2829            if (!maybeMetadata) {
   2830              // Unknown directories during clearing are allowed. Just
   2831              // warn if we find them.
   2832              UNKNOWN_FILE_WARNING(leafName);
   2833              break;
   2834            }
   2835 
   2836            auto metadata = maybeMetadata.extract();
   2837 
   2838            MOZ_ASSERT(metadata.mPersistenceType == aPersistenceType);
   2839 
   2840            // Skip the origin directory if it doesn't match the pattern.
   2841            if (!originScope.Matches(OriginScope::FromOrigin(metadata))) {
   2842              break;
   2843            }
   2844 
   2845            // We can't guarantee that this will always succeed on
   2846            // Windows...
   2847            QM_WARNONLY_TRY(
   2848                aQuotaManager.RemoveOriginDirectory(*file), [&](const auto&) {
   2849                  directoriesForRemovalRetry.AppendElement(std::move(file));
   2850                });
   2851 
   2852            mOriginMetadataArray.AppendElement(metadata);
   2853 
   2854            const bool initialized =
   2855                aPersistenceType == PERSISTENCE_TYPE_PERSISTENT
   2856                    ? aQuotaManager.IsPersistentOriginInitializedInternal(
   2857                          metadata.mOrigin)
   2858                    : aQuotaManager.IsTemporaryStorageInitializedInternal();
   2859 
   2860            // If it hasn't been initialized, we don't need to update the
   2861            // quota and notify the removing client, but we do need to remove
   2862            // it from quota info cache.
   2863            if (!initialized) {
   2864              aQuotaManager.RemoveOriginFromCache(metadata);
   2865              break;
   2866            }
   2867 
   2868            if (aPersistenceType != PERSISTENCE_TYPE_PERSISTENT) {
   2869              aQuotaManager.RemoveQuotaForOrigin(aPersistenceType, metadata);
   2870            }
   2871 
   2872            aQuotaManager.OriginClearCompleted(
   2873                metadata, ClientStorageScope::CreateFromNull());
   2874 
   2875            break;
   2876          }
   2877 
   2878          case nsIFileKind::ExistsAsFile: {
   2879            // Unknown files during clearing are allowed. Just warn if we
   2880            // find them.
   2881            if (!IsOSMetadata(leafName)) {
   2882              UNKNOWN_FILE_WARNING(leafName);
   2883            }
   2884 
   2885            break;
   2886          }
   2887 
   2888          case nsIFileKind::DoesNotExist: {
   2889            if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
   2890              break;
   2891            }
   2892 
   2893            QM_TRY_UNWRAP(auto metadata, aQuotaManager.GetOriginMetadata(file));
   2894 
   2895            MOZ_ASSERT(metadata.mPersistenceType == aPersistenceType);
   2896 
   2897            // Skip the origin directory if it doesn't match the pattern.
   2898            if (!originScope.Matches(OriginScope::FromOrigin(metadata))) {
   2899              break;
   2900            }
   2901 
   2902            if (!aQuotaManager.IsPendingOrigin(metadata)) {
   2903              break;
   2904            }
   2905 
   2906            mOriginMetadataArray.AppendElement(metadata);
   2907 
   2908            aQuotaManager.RemoveQuotaForOrigin(aPersistenceType, metadata);
   2909 
   2910            aQuotaManager.OriginClearCompleted(
   2911                metadata, ClientStorageScope::CreateFromNull());
   2912 
   2913            break;
   2914          }
   2915        }
   2916 
   2917        mIterations++;
   2918        aQuotaManager.IncreaseTotalDirectoryIterations();
   2919 
   2920        return Ok{};
   2921      }),
   2922      QM_VOID);
   2923 
   2924  // Retry removing any directories that failed to be removed earlier now.
   2925  //
   2926  // XXX This will still block this operation. We might instead dispatch a
   2927  // runnable to our own thread for each retry round with a timer. We must
   2928  // ensure that the directory lock is upheld until we complete or give up
   2929  // though.
   2930  for (uint32_t index = 0; index < 10; index++) {
   2931    aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
   2932      return nsPrintfCString(
   2933          "ClearRequestBase: Starting repeated directory removal #%d", index);
   2934    });
   2935 
   2936    for (auto&& file : std::exchange(directoriesForRemovalRetry,
   2937                                     nsTArray<nsCOMPtr<nsIFile>>{})) {
   2938      QM_WARNONLY_TRY(
   2939          aQuotaManager.RemoveOriginDirectory(*file),
   2940          ([&directoriesForRemovalRetry, &file](const auto&) {
   2941            directoriesForRemovalRetry.AppendElement(std::move(file));
   2942          }));
   2943    }
   2944 
   2945    aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
   2946      return nsPrintfCString(
   2947          "ClearRequestBase: Completed repeated directory removal #%d", index);
   2948    });
   2949 
   2950    if (directoriesForRemovalRetry.IsEmpty()) {
   2951      break;
   2952    }
   2953 
   2954    aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
   2955      return nsPrintfCString("ClearRequestBase: Before sleep #%d", index);
   2956    });
   2957 
   2958    PR_Sleep(PR_MillisecondsToInterval(200));
   2959 
   2960    aQuotaManager.MaybeRecordQuotaManagerShutdownStepWith([index]() {
   2961      return nsPrintfCString("ClearRequestBase: After sleep #%d", index);
   2962    });
   2963  }
   2964 
   2965  QM_WARNONLY_TRY(OkIf(directoriesForRemovalRetry.IsEmpty()));
   2966 
   2967  aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
   2968      "ClearRequestBase: Completed deleting files"_ns);
   2969 }
   2970 
   2971 ClearOriginOp::ClearOriginOp(
   2972    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   2973    const mozilla::Maybe<PersistenceType>& aPersistenceType,
   2974    const PrincipalInfo& aPrincipalInfo)
   2975    : ClearRequestBase(std::move(aQuotaManager), "dom::quota::ClearOriginOp"),
   2976      mPrincipalInfo(aPrincipalInfo),
   2977      mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
   2978                                               *aPersistenceType)
   2979                                         : PersistenceScope::CreateFromNull()) {
   2980  AssertIsOnOwningThread();
   2981 }
   2982 
   2983 nsresult ClearOriginOp::DoInit(QuotaManager& aQuotaManager) {
   2984  AssertIsOnOwningThread();
   2985 
   2986  QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
   2987                                        aQuotaManager, mPrincipalInfo));
   2988 
   2989  mPrincipalMetadata.AssertInvariants();
   2990 
   2991  return NS_OK;
   2992 }
   2993 
   2994 RefPtr<BoolPromise> ClearOriginOp::OpenDirectory() {
   2995  AssertIsOnOwningThread();
   2996 
   2997  return OpenStorageDirectory(
   2998      mPersistenceScope, OriginScope::FromOrigin(mPrincipalMetadata),
   2999      ClientStorageScope::CreateFromNull(), /* aExclusive */ true,
   3000      /* aInitializeOrigins */ false, DirectoryLockCategory::UninitOrigins);
   3001 }
   3002 
   3003 nsresult ClearOriginOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   3004  AssertIsOnIOThread();
   3005  aQuotaManager.AssertStorageIsInitializedInternal();
   3006 
   3007  AUTO_PROFILER_LABEL("ClearRequestBase::DoDirectoryWork", OTHER);
   3008 
   3009  if (mPersistenceScope.IsNull()) {
   3010    for (const PersistenceType type : kAllPersistenceTypes) {
   3011      DeleteFiles(aQuotaManager, OriginMetadata(mPrincipalMetadata, type));
   3012    }
   3013  } else {
   3014    MOZ_ASSERT(mPersistenceScope.IsValue());
   3015 
   3016    DeleteFiles(aQuotaManager, OriginMetadata(mPrincipalMetadata,
   3017                                              mPersistenceScope.GetValue()));
   3018  }
   3019 
   3020  return NS_OK;
   3021 }
   3022 
   3023 OriginMetadataArray ClearOriginOp::UnwrapResolveValue() {
   3024  AssertIsOnOwningThread();
   3025 
   3026  return std::move(mOriginMetadataArray);
   3027 }
   3028 
   3029 void ClearOriginOp::CloseDirectory() {
   3030  AssertIsOnOwningThread();
   3031 
   3032  SafeDropDirectoryLock(mDirectoryLock);
   3033 }
   3034 
   3035 ClearClientOp::ClearClientOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   3036                             mozilla::Maybe<PersistenceType> aPersistenceType,
   3037                             const PrincipalInfo& aPrincipalInfo,
   3038                             Client::Type aClientType)
   3039    : OpenStorageDirectoryHelper(std::move(aQuotaManager),
   3040                                 "dom::quota::ClearClientOp"),
   3041      mPrincipalInfo(aPrincipalInfo),
   3042      mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
   3043                                               *aPersistenceType)
   3044                                         : PersistenceScope::CreateFromNull()),
   3045      mClientType(aClientType) {
   3046  AssertIsOnOwningThread();
   3047 }
   3048 
   3049 nsresult ClearClientOp::DoInit(QuotaManager& aQuotaManager) {
   3050  AssertIsOnOwningThread();
   3051 
   3052  QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
   3053                                        aQuotaManager, mPrincipalInfo));
   3054 
   3055  mPrincipalMetadata.AssertInvariants();
   3056 
   3057  return NS_OK;
   3058 }
   3059 
   3060 RefPtr<BoolPromise> ClearClientOp::OpenDirectory() {
   3061  AssertIsOnOwningThread();
   3062 
   3063  return OpenStorageDirectory(
   3064      mPersistenceScope, OriginScope::FromOrigin(mPrincipalMetadata),
   3065      ClientStorageScope::CreateFromClient(mClientType), /* aExclusive */ true,
   3066      /* aInitializeOrigins */ false, DirectoryLockCategory::UninitClients);
   3067 }
   3068 
   3069 void ClearClientOp::DeleteFiles(const ClientMetadata& aClientMetadata) {
   3070  AssertIsOnIOThread();
   3071 
   3072  QM_TRY(
   3073      MOZ_TO_RESULT(mQuotaManager->AboutToClearOrigins(
   3074          PersistenceScope::CreateFromValue(aClientMetadata.mPersistenceType),
   3075          OriginScope::FromOrigin(aClientMetadata),
   3076          ClientStorageScope::CreateFromClient(aClientMetadata.mClientType))),
   3077      QM_VOID);
   3078 
   3079  QM_TRY_INSPECT(const auto& directory,
   3080                 mQuotaManager->GetOriginDirectory(aClientMetadata), QM_VOID);
   3081 
   3082  QM_TRY(MOZ_TO_RESULT(directory->Append(
   3083             Client::TypeToString(aClientMetadata.mClientType))),
   3084         QM_VOID);
   3085 
   3086  QM_TRY_INSPECT(const bool& exists,
   3087                 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists), QM_VOID);
   3088  if (!exists) {
   3089    return;
   3090  }
   3091 
   3092  QM_TRY(MOZ_TO_RESULT(directory->Remove(true)), QM_VOID);
   3093 
   3094  mClientMetadataArray.AppendElement(aClientMetadata);
   3095 
   3096  const bool initialized =
   3097      aClientMetadata.mPersistenceType == PERSISTENCE_TYPE_PERSISTENT
   3098          ? mQuotaManager->IsPersistentOriginInitializedInternal(
   3099                aClientMetadata.mOrigin)
   3100          : mQuotaManager->IsTemporaryStorageInitializedInternal();
   3101 
   3102  if (!initialized) {
   3103    return;
   3104  }
   3105 
   3106  if (aClientMetadata.mPersistenceType != PERSISTENCE_TYPE_PERSISTENT) {
   3107    mQuotaManager->ResetUsageForClient(aClientMetadata);
   3108  }
   3109 
   3110  mQuotaManager->OriginClearCompleted(
   3111      aClientMetadata,
   3112      ClientStorageScope::CreateFromClient(aClientMetadata.mClientType));
   3113 }
   3114 
   3115 nsresult ClearClientOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   3116  AssertIsOnIOThread();
   3117  aQuotaManager.AssertStorageIsInitializedInternal();
   3118 
   3119  AUTO_PROFILER_LABEL("ClearClientOp::DoDirectoryWork", OTHER);
   3120 
   3121  if (mPersistenceScope.IsNull()) {
   3122    for (const PersistenceType type : kAllPersistenceTypes) {
   3123      DeleteFiles(ClientMetadata(OriginMetadata(mPrincipalMetadata, type),
   3124                                 mClientType));
   3125    }
   3126  } else {
   3127    MOZ_ASSERT(mPersistenceScope.IsValue());
   3128 
   3129    DeleteFiles(ClientMetadata(
   3130        OriginMetadata(mPrincipalMetadata, mPersistenceScope.GetValue()),
   3131        mClientType));
   3132  }
   3133 
   3134  return NS_OK;
   3135 }
   3136 
   3137 ClientMetadataArray ClearClientOp::UnwrapResolveValue() {
   3138  AssertIsOnOwningThread();
   3139 
   3140  return std::move(mClientMetadataArray);
   3141 }
   3142 
   3143 void ClearClientOp::CloseDirectory() {
   3144  AssertIsOnOwningThread();
   3145 
   3146  SafeDropDirectoryLock(mDirectoryLock);
   3147 }
   3148 
   3149 ClearStoragesForOriginPrefixOp::ClearStoragesForOriginPrefixOp(
   3150    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   3151    const Maybe<PersistenceType>& aPersistenceType,
   3152    const PrincipalInfo& aPrincipalInfo)
   3153    : OpenStorageDirectoryHelper(std::move(aQuotaManager),
   3154                                 "dom::quota::ClearStoragesForOriginPrefixOp"),
   3155      mPrincipalInfo(aPrincipalInfo),
   3156      mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
   3157                                               *aPersistenceType)
   3158                                         : PersistenceScope::CreateFromNull()) {
   3159  AssertIsOnOwningThread();
   3160 }
   3161 
   3162 nsresult ClearStoragesForOriginPrefixOp::DoInit(QuotaManager& aQuotaManager) {
   3163  AssertIsOnOwningThread();
   3164 
   3165  QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
   3166                                        aQuotaManager, mPrincipalInfo));
   3167 
   3168  mPrincipalMetadata.AssertInvariants();
   3169 
   3170  return NS_OK;
   3171 }
   3172 
   3173 RefPtr<BoolPromise> ClearStoragesForOriginPrefixOp::OpenDirectory() {
   3174  AssertIsOnOwningThread();
   3175 
   3176  return OpenStorageDirectory(
   3177      mPersistenceScope, OriginScope::FromPrefix(mPrincipalMetadata),
   3178      ClientStorageScope::CreateFromNull(), /* aExclusive */ true,
   3179      /* aInitializeOrigins */ false, DirectoryLockCategory::UninitOrigins);
   3180 }
   3181 
   3182 nsresult ClearStoragesForOriginPrefixOp::DoDirectoryWork(
   3183    QuotaManager& aQuotaManager) {
   3184  AssertIsOnIOThread();
   3185 
   3186  AUTO_PROFILER_LABEL("ClearStoragesForOriginPrefixOp::DoDirectoryWork", OTHER);
   3187 
   3188  if (mPersistenceScope.IsNull()) {
   3189    for (const PersistenceType type : kAllPersistenceTypes) {
   3190      DeleteFiles(aQuotaManager, type,
   3191                  OriginScope::FromPrefix(mPrincipalMetadata));
   3192    }
   3193  } else {
   3194    MOZ_ASSERT(mPersistenceScope.IsValue());
   3195 
   3196    DeleteFiles(aQuotaManager, mPersistenceScope.GetValue(),
   3197                OriginScope::FromPrefix(mPrincipalMetadata));
   3198  }
   3199 
   3200  return NS_OK;
   3201 }
   3202 
   3203 OriginMetadataArray ClearStoragesForOriginPrefixOp::UnwrapResolveValue() {
   3204  AssertIsOnOwningThread();
   3205 
   3206  return std::move(mOriginMetadataArray);
   3207 }
   3208 
   3209 void ClearStoragesForOriginPrefixOp::CloseDirectory() {
   3210  AssertIsOnOwningThread();
   3211 
   3212  SafeDropDirectoryLock(mDirectoryLock);
   3213 }
   3214 
   3215 ClearDataOp::ClearDataOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   3216                         const OriginAttributesPattern& aPattern)
   3217    : ClearRequestBase(std::move(aQuotaManager), "dom::quota::ClearDataOp"),
   3218      mPattern(aPattern) {}
   3219 
   3220 RefPtr<BoolPromise> ClearDataOp::OpenDirectory() {
   3221  AssertIsOnOwningThread();
   3222 
   3223  return OpenStorageDirectory(
   3224      PersistenceScope::CreateFromNull(), OriginScope::FromPattern(mPattern),
   3225      ClientStorageScope::CreateFromNull(), /* aExclusive */ true,
   3226      /* aInitializeOrigins */ false, DirectoryLockCategory::UninitOrigins);
   3227 }
   3228 
   3229 nsresult ClearDataOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   3230  AssertIsOnIOThread();
   3231 
   3232  AUTO_PROFILER_LABEL("ClearRequestBase::DoDirectoryWork", OTHER);
   3233 
   3234  // Optimize clearing of thumbnail private identity temporary origins by
   3235  // skipping potentially expensive temporary repository traversals when there
   3236  // are no thumbnail private identity temporary origins (this is especially
   3237  // important during shutdown).
   3238  //
   3239  // XXX Can we do the skipping also when temporary storage is not initialized
   3240  // (no new thumbnail private identity temporary origins could be created yet)?
   3241  if (aQuotaManager.IsThumbnailPrivateIdentityIdKnown() &&
   3242      IsUserContextPattern(mPattern,
   3243                           aQuotaManager.GetThumbnailPrivateIdentityId()) &&
   3244      aQuotaManager.IsTemporaryStorageInitializedInternal() &&
   3245      aQuotaManager.ThumbnailPrivateIdentityTemporaryOriginCount() == 0) {
   3246    DeleteFiles(aQuotaManager, PERSISTENCE_TYPE_PERSISTENT,
   3247                OriginScope::FromPattern(mPattern));
   3248 
   3249    return NS_OK;
   3250  }
   3251 
   3252  for (const PersistenceType type : kAllPersistenceTypes) {
   3253    DeleteFiles(aQuotaManager, type, OriginScope::FromPattern(mPattern));
   3254  }
   3255 
   3256  return NS_OK;
   3257 }
   3258 
   3259 OriginMetadataArray ClearDataOp::UnwrapResolveValue() {
   3260  AssertIsOnOwningThread();
   3261 
   3262  return std::move(mOriginMetadataArray);
   3263 }
   3264 
   3265 void ClearDataOp::CloseDirectory() {
   3266  AssertIsOnOwningThread();
   3267 
   3268  SafeDropDirectoryLock(mDirectoryLock);
   3269 }
   3270 
   3271 ShutdownOriginOp::ShutdownOriginOp(
   3272    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   3273    mozilla::Maybe<PersistenceType> aPersistenceType,
   3274    const PrincipalInfo& aPrincipalInfo)
   3275    : ResolvableNormalOriginOp(std::move(aQuotaManager),
   3276                               "dom::quota::ShutdownOriginOp"),
   3277      mPrincipalInfo(aPrincipalInfo),
   3278      mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
   3279                                               *aPersistenceType)
   3280                                         : PersistenceScope::CreateFromNull()) {
   3281  AssertIsOnOwningThread();
   3282 }
   3283 
   3284 nsresult ShutdownOriginOp::DoInit(QuotaManager& aQuotaManager) {
   3285  AssertIsOnOwningThread();
   3286 
   3287  QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
   3288                                        aQuotaManager, mPrincipalInfo));
   3289 
   3290  mPrincipalMetadata.AssertInvariants();
   3291 
   3292  return NS_OK;
   3293 }
   3294 
   3295 RefPtr<BoolPromise> ShutdownOriginOp::OpenDirectory() {
   3296  AssertIsOnOwningThread();
   3297 
   3298  mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
   3299      mPersistenceScope, OriginScope::FromOrigin(mPrincipalMetadata),
   3300      ClientStorageScope::CreateFromNull(), /* aExclusive */ true,
   3301      DirectoryLockCategory::UninitOrigins);
   3302 
   3303  return mDirectoryLock->Acquire();
   3304 }
   3305 
   3306 void ShutdownOriginOp::CollectOriginMetadata(
   3307    const OriginMetadata& aOriginMetadata) {
   3308  AssertIsOnIOThread();
   3309 
   3310  QM_TRY_INSPECT(const auto& directory,
   3311                 mQuotaManager->GetOriginDirectory(aOriginMetadata), QM_VOID);
   3312 
   3313  QM_TRY_INSPECT(const bool& exists,
   3314                 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists), QM_VOID);
   3315  if (!exists) {
   3316    if (aOriginMetadata.mPersistenceType != PERSISTENCE_TYPE_PERSISTENT &&
   3317        mQuotaManager->IsPendingOrigin(aOriginMetadata)) {
   3318      mOriginMetadataArray.AppendElement(aOriginMetadata);
   3319    }
   3320 
   3321    return;
   3322  }
   3323 
   3324  mOriginMetadataArray.AppendElement(aOriginMetadata);
   3325 }
   3326 
   3327 nsresult ShutdownOriginOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   3328  AssertIsOnIOThread();
   3329 
   3330  AUTO_PROFILER_LABEL("ShutdownOriginOp::DoDirectoryWork", OTHER);
   3331 
   3332  if (mPersistenceScope.IsNull()) {
   3333    for (const PersistenceType type : kAllPersistenceTypes) {
   3334      CollectOriginMetadata(OriginMetadata(mPrincipalMetadata, type));
   3335    }
   3336  } else {
   3337    MOZ_ASSERT(mPersistenceScope.IsValue());
   3338 
   3339    CollectOriginMetadata(
   3340        OriginMetadata(mPrincipalMetadata, mPersistenceScope.GetValue()));
   3341  }
   3342 
   3343  return NS_OK;
   3344 }
   3345 
   3346 OriginMetadataArray ShutdownOriginOp::UnwrapResolveValue() {
   3347  AssertIsOnOwningThread();
   3348 
   3349  return std::move(mOriginMetadataArray);
   3350 }
   3351 
   3352 void ShutdownOriginOp::CloseDirectory() {
   3353  AssertIsOnOwningThread();
   3354 
   3355  DropDirectoryLockIfNotDropped(mDirectoryLock);
   3356 }
   3357 
   3358 ShutdownClientOp::ShutdownClientOp(
   3359    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   3360    mozilla::Maybe<PersistenceType> aPersistenceType,
   3361    const PrincipalInfo& aPrincipalInfo, Client::Type aClientType)
   3362    : ResolvableNormalOriginOp(std::move(aQuotaManager),
   3363                               "dom::quota::ShutdownClientOp"),
   3364      mPrincipalInfo(aPrincipalInfo),
   3365      mPersistenceScope(aPersistenceType ? PersistenceScope::CreateFromValue(
   3366                                               *aPersistenceType)
   3367                                         : PersistenceScope::CreateFromNull()),
   3368      mClientType(aClientType) {
   3369  AssertIsOnOwningThread();
   3370 }
   3371 
   3372 nsresult ShutdownClientOp::DoInit(QuotaManager& aQuotaManager) {
   3373  AssertIsOnOwningThread();
   3374 
   3375  QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
   3376                                        aQuotaManager, mPrincipalInfo));
   3377 
   3378  mPrincipalMetadata.AssertInvariants();
   3379 
   3380  return NS_OK;
   3381 }
   3382 
   3383 RefPtr<BoolPromise> ShutdownClientOp::OpenDirectory() {
   3384  AssertIsOnOwningThread();
   3385 
   3386  mDirectoryLock = mQuotaManager->CreateDirectoryLockInternal(
   3387      mPersistenceScope, OriginScope::FromOrigin(mPrincipalMetadata),
   3388      ClientStorageScope::CreateFromClient(mClientType), /* aExclusive */ true,
   3389      DirectoryLockCategory::UninitClients);
   3390 
   3391  return mDirectoryLock->Acquire();
   3392 }
   3393 
   3394 void ShutdownClientOp::CollectOriginMetadata(
   3395    const ClientMetadata& aClientMetadata) {
   3396  AssertIsOnIOThread();
   3397 
   3398  QM_TRY_INSPECT(const auto& directory,
   3399                 mQuotaManager->GetOriginDirectory(aClientMetadata), QM_VOID);
   3400 
   3401  QM_TRY(MOZ_TO_RESULT(directory->Append(
   3402             Client::TypeToString(aClientMetadata.mClientType))),
   3403         QM_VOID);
   3404 
   3405  QM_TRY_INSPECT(const bool& exists,
   3406                 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists), QM_VOID);
   3407  if (!exists) {
   3408    return;
   3409  }
   3410 
   3411  mClientMetadataArray.AppendElement(aClientMetadata);
   3412 }
   3413 
   3414 nsresult ShutdownClientOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   3415  AssertIsOnIOThread();
   3416 
   3417  AUTO_PROFILER_LABEL("ShutdownClientOp::DoDirectoryWork", OTHER);
   3418 
   3419  if (mPersistenceScope.IsNull()) {
   3420    for (const PersistenceType type : kAllPersistenceTypes) {
   3421      CollectOriginMetadata(ClientMetadata(
   3422          OriginMetadata(mPrincipalMetadata, type), mClientType));
   3423    }
   3424  } else {
   3425    MOZ_ASSERT(mPersistenceScope.IsValue());
   3426 
   3427    CollectOriginMetadata(ClientMetadata(
   3428        OriginMetadata(mPrincipalMetadata, mPersistenceScope.GetValue()),
   3429        mClientType));
   3430  }
   3431 
   3432  return NS_OK;
   3433 }
   3434 
   3435 ClientMetadataArray ShutdownClientOp::UnwrapResolveValue() {
   3436  AssertIsOnOwningThread();
   3437 
   3438  return std::move(mClientMetadataArray);
   3439 }
   3440 
   3441 void ShutdownClientOp::CloseDirectory() {
   3442  AssertIsOnOwningThread();
   3443 
   3444  DropDirectoryLockIfNotDropped(mDirectoryLock);
   3445 }
   3446 
   3447 PersistRequestBase::PersistRequestBase(
   3448    MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   3449    const PrincipalInfo& aPrincipalInfo)
   3450    : OpenStorageDirectoryHelper(std::move(aQuotaManager),
   3451                                 "dom::quota::PersistRequestBase"),
   3452      mPrincipalInfo(aPrincipalInfo) {
   3453  AssertIsOnOwningThread();
   3454 }
   3455 
   3456 nsresult PersistRequestBase::DoInit(QuotaManager& aQuotaManager) {
   3457  AssertIsOnOwningThread();
   3458 
   3459  // Figure out which origin we're dealing with.
   3460  QM_TRY_UNWRAP(mPrincipalMetadata, GetInfoFromValidatedPrincipalInfo(
   3461                                        aQuotaManager, mPrincipalInfo));
   3462 
   3463  mPrincipalMetadata.AssertInvariants();
   3464 
   3465  return NS_OK;
   3466 }
   3467 
   3468 RefPtr<BoolPromise> PersistRequestBase::OpenDirectory() {
   3469  AssertIsOnOwningThread();
   3470 
   3471  return OpenStorageDirectory(
   3472      PersistenceScope::CreateFromValue(PERSISTENCE_TYPE_DEFAULT),
   3473      OriginScope::FromOrigin(mPrincipalMetadata),
   3474      ClientStorageScope::CreateFromNull(),
   3475      /* aExclusive */ false);
   3476 }
   3477 
   3478 void PersistRequestBase::CloseDirectory() {
   3479  AssertIsOnOwningThread();
   3480 
   3481  SafeDropDirectoryLock(mDirectoryLock);
   3482 }
   3483 
   3484 PersistedOp::PersistedOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   3485                         const RequestParams& aParams)
   3486    : PersistRequestBase(std::move(aQuotaManager),
   3487                         aParams.get_PersistedParams().principalInfo()),
   3488      mPersisted(false) {
   3489  MOZ_ASSERT(aParams.type() == RequestParams::TPersistedParams);
   3490 }
   3491 
   3492 nsresult PersistedOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   3493  AssertIsOnIOThread();
   3494  aQuotaManager.AssertStorageIsInitializedInternal();
   3495 
   3496  AUTO_PROFILER_LABEL("PersistedOp::DoDirectoryWork", OTHER);
   3497 
   3498  const OriginMetadata originMetadata = {mPrincipalMetadata,
   3499                                         PERSISTENCE_TYPE_DEFAULT};
   3500 
   3501  Nullable<bool> persisted = aQuotaManager.OriginPersisted(originMetadata);
   3502 
   3503  if (!persisted.IsNull()) {
   3504    mPersisted = persisted.Value();
   3505    return NS_OK;
   3506  }
   3507 
   3508  // If we get here, it means the origin hasn't been initialized yet.
   3509  // Try to get the persisted flag from directory metadata on disk.
   3510 
   3511  QM_TRY_INSPECT(const auto& directory,
   3512                 aQuotaManager.GetOriginDirectory(originMetadata));
   3513 
   3514  QM_TRY_INSPECT(const bool& exists,
   3515                 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
   3516 
   3517  if (exists) {
   3518    // Get the metadata. We only use the persisted flag.
   3519    QM_TRY_INSPECT(const auto& metadata,
   3520                   aQuotaManager.LoadFullOriginMetadataWithRestore(directory));
   3521 
   3522    mPersisted = metadata.mPersisted;
   3523  } else {
   3524    // The directory has not been created yet.
   3525    mPersisted = false;
   3526  }
   3527 
   3528  return NS_OK;
   3529 }
   3530 
   3531 void PersistedOp::GetResponse(RequestResponse& aResponse) {
   3532  AssertIsOnOwningThread();
   3533 
   3534  PersistedResponse persistedResponse;
   3535  persistedResponse.persisted() = mPersisted;
   3536 
   3537  aResponse = persistedResponse;
   3538 }
   3539 
   3540 PersistOp::PersistOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   3541                     const RequestParams& aParams)
   3542    : PersistRequestBase(std::move(aQuotaManager),
   3543                         aParams.get_PersistParams().principalInfo()) {
   3544  MOZ_ASSERT(aParams.type() == RequestParams::TPersistParams);
   3545 }
   3546 
   3547 nsresult PersistOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   3548  AssertIsOnIOThread();
   3549  aQuotaManager.AssertStorageIsInitializedInternal();
   3550 
   3551  const OriginMetadata originMetadata = {mPrincipalMetadata,
   3552                                         PERSISTENCE_TYPE_DEFAULT};
   3553 
   3554  AUTO_PROFILER_LABEL("PersistOp::DoDirectoryWork", OTHER);
   3555 
   3556  // Update directory metadata on disk first. Then, create/update the
   3557  // originInfo if needed.
   3558 
   3559  QM_TRY_INSPECT(const auto& directory,
   3560                 aQuotaManager.GetOriginDirectory(originMetadata));
   3561 
   3562  QM_TRY_INSPECT(const bool& created,
   3563                 aQuotaManager.EnsureOriginDirectory(*directory));
   3564 
   3565  if (created) {
   3566    // A new origin directory has been created.
   3567 
   3568    const auto [timestamp, maintenanceDate, accessed] = [&aQuotaManager,
   3569                                                         &originMetadata]() {
   3570      // Update OriginInfo too if temporary origin was already initialized.
   3571      if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
   3572        if (aQuotaManager.IsTemporaryOriginInitializedInternal(
   3573                originMetadata)) {
   3574          // We have a temporary origin which has been initialized without
   3575          // ensuring respective origin directory. So OriginInfo already exists
   3576          // and it needs to be updated because the origin directory has been
   3577          // just created.
   3578 
   3579          return aQuotaManager.WithOriginInfo(
   3580              originMetadata, [](const auto& originInfo) {
   3581                const int64_t timestamp = originInfo->LockedAccessTime();
   3582                const int32_t maintenanceDate =
   3583                    originInfo->LockedMaintenanceDate();
   3584                const bool accessed = originInfo->LockedAccessed();
   3585 
   3586                originInfo->LockedDirectoryCreated();
   3587 
   3588                return std::make_tuple(timestamp, maintenanceDate, accessed);
   3589              });
   3590        }
   3591      }
   3592 
   3593      const int64_t timestamp = PR_Now();
   3594 
   3595      return std::make_tuple(
   3596          /* timestamp */ timestamp,
   3597          /* maintenanceDate */ Date::FromTimestamp(timestamp).ToDays(),
   3598          /* accessed */ false);
   3599    }();
   3600 
   3601    FullOriginMetadata fullOriginMetadata = FullOriginMetadata{
   3602        originMetadata,
   3603        OriginStateMetadata{timestamp, maintenanceDate, accessed,
   3604                            /* aPersisted */ true},
   3605        ClientUsageArray(), /* aUsage */ 0, kCurrentQuotaVersion};
   3606 
   3607    if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
   3608      // Usually, infallible operations are placed after fallible ones.
   3609      // However, since we lack atomic support for creating the origin
   3610      // directory along with its metadata, we need to add the origin to cached
   3611      // origins right after directory creation.
   3612      aQuotaManager.AddTemporaryOrigin(fullOriginMetadata);
   3613    }
   3614 
   3615    QM_TRY(MOZ_TO_RESULT(QuotaManager::CreateDirectoryMetadata2(
   3616        *directory, fullOriginMetadata)));
   3617 
   3618    // Update or create OriginInfo too if temporary storage was already
   3619    // initialized.
   3620    if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
   3621      if (aQuotaManager.IsTemporaryOriginInitializedInternal(originMetadata)) {
   3622        // In this case, we have a temporary origin which has been initialized
   3623        // without ensuring respective origin directory. So OriginInfo already
   3624        // exists and it needs to be updated because the origin directory has
   3625        // been just created.
   3626 
   3627        aQuotaManager.PersistOrigin(originMetadata);
   3628      } else {
   3629        // In this case, we have a temporary origin which hasn't been
   3630        // initialized yet. So OriginInfo needs to be created because the
   3631        // origin directory has been just created.
   3632 
   3633        aQuotaManager.InitQuotaForOrigin(fullOriginMetadata);
   3634      }
   3635    }
   3636  } else {
   3637    QM_TRY_UNWRAP(
   3638        OriginStateMetadata originStateMetadata,
   3639        ([&aQuotaManager, &originMetadata,
   3640          &directory]() -> mozilla::Result<OriginStateMetadata, nsresult> {
   3641          Maybe<OriginStateMetadata> maybeOriginStateMetadata =
   3642              aQuotaManager.IsTemporaryStorageInitializedInternal()
   3643                  ? aQuotaManager.GetOriginStateMetadata(originMetadata)
   3644                  : Nothing();
   3645 
   3646          if (maybeOriginStateMetadata) {
   3647            return maybeOriginStateMetadata.extract();
   3648          }
   3649 
   3650          // Get the metadata (restore the metadata file if necessary). We only
   3651          // use the origin state metadata.
   3652          QM_TRY_INSPECT(
   3653              const auto& metadata,
   3654              aQuotaManager.LoadFullOriginMetadataWithRestore(directory));
   3655 
   3656          return metadata;
   3657        }()));
   3658 
   3659    if (!originStateMetadata.mPersisted) {
   3660      // Set the persisted flag to true and also update origin access time
   3661      // while we are here.
   3662 
   3663      // See the documentation for this pref in StaticPrefList.yaml
   3664      if (StaticPrefs::
   3665              dom_quotaManager_temporaryStorage_updateOriginAccessTime()) {
   3666        originStateMetadata.mLastAccessTime = PR_Now();
   3667      }
   3668 
   3669      originStateMetadata.mPersisted = true;
   3670 
   3671      QM_TRY(MOZ_TO_RESULT(
   3672          SaveDirectoryMetadataHeader(*directory, originStateMetadata)));
   3673 
   3674      // Directory metadata has been successfully updated.
   3675      // Update OriginInfo too if temporary storage was already initialized.
   3676      if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
   3677        aQuotaManager.PersistOrigin(originMetadata);
   3678 
   3679        // XXX The origin access time should be updated too (but not the
   3680        // accessed flag).
   3681      }
   3682    }
   3683  }
   3684 
   3685  return NS_OK;
   3686 }
   3687 
   3688 void PersistOp::GetResponse(RequestResponse& aResponse) {
   3689  AssertIsOnOwningThread();
   3690 
   3691  aResponse = PersistResponse();
   3692 }
   3693 
   3694 EstimateOp::EstimateOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
   3695                       const EstimateParams& aParams)
   3696    : OpenStorageDirectoryHelper(std::move(aQuotaManager),
   3697                                 "dom::quota::EstimateOp"),
   3698      mParams(aParams) {
   3699  AssertIsOnOwningThread();
   3700 }
   3701 
   3702 nsresult EstimateOp::DoInit(QuotaManager& aQuotaManager) {
   3703  AssertIsOnOwningThread();
   3704 
   3705  QM_TRY_UNWRAP(PrincipalMetadata principalMetadata,
   3706                GetInfoFromValidatedPrincipalInfo(aQuotaManager,
   3707                                                  mParams.principalInfo()));
   3708 
   3709  principalMetadata.AssertInvariants();
   3710 
   3711  mOriginMetadata = {std::move(principalMetadata), PERSISTENCE_TYPE_DEFAULT};
   3712 
   3713  return NS_OK;
   3714 }
   3715 
   3716 RefPtr<BoolPromise> EstimateOp::OpenDirectory() {
   3717  AssertIsOnOwningThread();
   3718 
   3719  return OpenStorageDirectory(
   3720      PersistenceScope::CreateFromSet(PERSISTENCE_TYPE_TEMPORARY,
   3721                                      PERSISTENCE_TYPE_DEFAULT,
   3722                                      PERSISTENCE_TYPE_PRIVATE),
   3723      OriginScope::FromGroup(mOriginMetadata.mGroup),
   3724      ClientStorageScope::CreateFromNull(),
   3725      /* aExclusive */ false,
   3726      /* aInitializeOrigins */ true);
   3727 }
   3728 
   3729 nsresult EstimateOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   3730  AssertIsOnIOThread();
   3731  aQuotaManager.AssertStorageIsInitializedInternal();
   3732 
   3733  AUTO_PROFILER_LABEL("EstimateOp::DoDirectoryWork", OTHER);
   3734 
   3735  // Get cached usage (the method doesn't have to stat any files).
   3736  mUsageAndLimit = aQuotaManager.GetUsageAndLimitForEstimate(mOriginMetadata);
   3737 
   3738  return NS_OK;
   3739 }
   3740 
   3741 void EstimateOp::GetResponse(RequestResponse& aResponse) {
   3742  AssertIsOnOwningThread();
   3743 
   3744  EstimateResponse estimateResponse;
   3745 
   3746  estimateResponse.usage() = mUsageAndLimit.first;
   3747  estimateResponse.limit() = mUsageAndLimit.second;
   3748 
   3749  aResponse = estimateResponse;
   3750 }
   3751 
   3752 void EstimateOp::CloseDirectory() {
   3753  AssertIsOnOwningThread();
   3754 
   3755  SafeDropDirectoryLock(mDirectoryLock);
   3756 }
   3757 
   3758 ListOriginsOp::ListOriginsOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager)
   3759    : OpenStorageDirectoryHelper(std::move(aQuotaManager),
   3760                                 "dom::quota::ListOriginsOp") {
   3761  AssertIsOnOwningThread();
   3762 }
   3763 
   3764 RefPtr<BoolPromise> ListOriginsOp::OpenDirectory() {
   3765  AssertIsOnOwningThread();
   3766 
   3767  return OpenStorageDirectory(PersistenceScope::CreateFromNull(),
   3768                              OriginScope::FromNull(),
   3769                              ClientStorageScope::CreateFromNull(),
   3770                              /* aExclusive */ false);
   3771 }
   3772 
   3773 nsresult ListOriginsOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
   3774  AssertIsOnIOThread();
   3775  aQuotaManager.AssertStorageIsInitializedInternal();
   3776 
   3777  AUTO_PROFILER_LABEL("ListOriginsOp::DoDirectoryWork", OTHER);
   3778 
   3779  for (const PersistenceType type : kAllPersistenceTypes) {
   3780    QM_TRY(MOZ_TO_RESULT(TraverseRepository(aQuotaManager, type)));
   3781  }
   3782 
   3783  // TraverseRepository above only consulted the file-system to get a list of
   3784  // known origins, but we also need to include origins that have pending
   3785  // quota usage.
   3786 
   3787  aQuotaManager.CollectPendingOriginsForListing([this](const auto& originInfo) {
   3788    mOrigins.AppendElement(originInfo->Origin());
   3789  });
   3790 
   3791  return NS_OK;
   3792 }
   3793 
   3794 const Atomic<bool>& ListOriginsOp::GetIsCanceledFlag() {
   3795  AssertIsOnIOThread();
   3796 
   3797  return Canceled();
   3798 }
   3799 
   3800 nsresult ListOriginsOp::ProcessOrigin(QuotaManager& aQuotaManager,
   3801                                      nsIFile& aOriginDir,
   3802                                      const bool aPersistent,
   3803                                      const PersistenceType aPersistenceType) {
   3804  AssertIsOnIOThread();
   3805 
   3806  QM_TRY_UNWRAP(auto maybeMetadata,
   3807                QM_OR_ELSE_WARN_IF(
   3808                    // Expression
   3809                    aQuotaManager.GetOriginMetadata(&aOriginDir)
   3810                        .map([](auto metadata) -> Maybe<OriginMetadata> {
   3811                          return Some(std::move(metadata));
   3812                        }),
   3813                    // Predicate.
   3814                    IsSpecificError<NS_ERROR_MALFORMED_URI>,
   3815                    // Fallback.
   3816                    ErrToDefaultOk<Maybe<OriginMetadata>>));
   3817 
   3818  if (!maybeMetadata) {
   3819    // Unknown directories during listing are allowed. Just warn if we find
   3820    // them.
   3821    QM_TRY_INSPECT(const auto& leafName,
   3822                   MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, aOriginDir,
   3823                                                     GetLeafName));
   3824 
   3825    UNKNOWN_FILE_WARNING(leafName);
   3826    return NS_OK;
   3827  }
   3828 
   3829  auto metadata = maybeMetadata.extract();
   3830 
   3831  if (aQuotaManager.IsOriginInternal(metadata.mOrigin)) {
   3832    return NS_OK;
   3833  }
   3834 
   3835  mOrigins.AppendElement(std::move(metadata.mOrigin));
   3836 
   3837  return NS_OK;
   3838 }
   3839 
   3840 CStringArray ListOriginsOp::UnwrapResolveValue() {
   3841  AssertIsOnOwningThread();
   3842  MOZ_ASSERT(!ResolveValueConsumed());
   3843 
   3844  return std::move(mOrigins);
   3845 }
   3846 
   3847 void ListOriginsOp::CloseDirectory() {
   3848  AssertIsOnOwningThread();
   3849 
   3850  SafeDropDirectoryLock(mDirectoryLock);
   3851 }
   3852 
   3853 }  // namespace mozilla::dom::quota