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