LCOV - code coverage report
Current view: top level - dom/quota - ActorsParent.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 4 3984 0.1 %
Date: 2017-07-14 16:53:18 Functions: 1 351 0.3 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "ActorsParent.h"
       8             : 
       9             : #include "mozIStorageConnection.h"
      10             : #include "mozIStorageService.h"
      11             : #include "nsIBinaryInputStream.h"
      12             : #include "nsIBinaryOutputStream.h"
      13             : #include "nsIFile.h"
      14             : #include "nsIFileStreams.h"
      15             : #include "nsIObserverService.h"
      16             : #include "nsIPermissionManager.h"
      17             : #include "nsIPrincipal.h"
      18             : #include "nsIRunnable.h"
      19             : #include "nsISimpleEnumerator.h"
      20             : #include "nsIScriptObjectPrincipal.h"
      21             : #include "nsIScriptSecurityManager.h"
      22             : #include "nsISupportsPrimitives.h"
      23             : #include "nsITimer.h"
      24             : #include "nsIURI.h"
      25             : #include "nsPIDOMWindow.h"
      26             : 
      27             : #include <algorithm>
      28             : #include "GeckoProfiler.h"
      29             : #include "mozilla/Atomics.h"
      30             : #include "mozilla/BasePrincipal.h"
      31             : #include "mozilla/CondVar.h"
      32             : #include "mozilla/dom/PContent.h"
      33             : #include "mozilla/dom/asmjscache/AsmJSCache.h"
      34             : #include "mozilla/dom/cache/QuotaClient.h"
      35             : #include "mozilla/dom/indexedDB/ActorsParent.h"
      36             : #include "mozilla/dom/quota/PQuotaParent.h"
      37             : #include "mozilla/dom/quota/PQuotaRequestParent.h"
      38             : #include "mozilla/dom/quota/PQuotaUsageRequestParent.h"
      39             : #include "mozilla/ipc/BackgroundParent.h"
      40             : #include "mozilla/ipc/BackgroundUtils.h"
      41             : #include "mozilla/IntegerRange.h"
      42             : #include "mozilla/Mutex.h"
      43             : #include "mozilla/LazyIdleThread.h"
      44             : #include "mozilla/Preferences.h"
      45             : #include "mozilla/Services.h"
      46             : #include "mozilla/StaticPtr.h"
      47             : #include "mozilla/TypeTraits.h"
      48             : #include "mozilla/Unused.h"
      49             : #include "mozStorageCID.h"
      50             : #include "mozStorageHelper.h"
      51             : #include "nsAppDirectoryServiceDefs.h"
      52             : #include "nsComponentManagerUtils.h"
      53             : #include "nsAboutProtocolUtils.h"
      54             : #include "nsCharSeparatedTokenizer.h"
      55             : #include "nsContentUtils.h"
      56             : #include "nsCRTGlue.h"
      57             : #include "nsDirectoryServiceUtils.h"
      58             : #include "nsEscape.h"
      59             : #include "nsNetUtil.h"
      60             : #include "nsPrintfCString.h"
      61             : #include "nsScriptSecurityManager.h"
      62             : #include "nsThreadUtils.h"
      63             : #include "nsXULAppAPI.h"
      64             : #include "prio.h"
      65             : #include "xpcpublic.h"
      66             : 
      67             : #include "OriginScope.h"
      68             : #include "QuotaManager.h"
      69             : #include "QuotaManagerService.h"
      70             : #include "QuotaObject.h"
      71             : #include "UsageInfo.h"
      72             : 
      73             : #define DISABLE_ASSERTS_FOR_FUZZING 0
      74             : 
      75             : #if DISABLE_ASSERTS_FOR_FUZZING
      76             : #define ASSERT_UNLESS_FUZZING(...) do { } while (0)
      77             : #else
      78             : #define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
      79             : #endif
      80             : 
      81             : #define UNKNOWN_FILE_WARNING(_leafName) \
      82             :   QM_WARNING("Something (%s) in the directory that doesn't belong!", \
      83             :              NS_ConvertUTF16toUTF8(leafName).get())
      84             : 
      85             : // The amount of time, in milliseconds, that our IO thread will stay alive
      86             : // after the last event it processes.
      87             : #define DEFAULT_THREAD_TIMEOUT_MS 30000
      88             : 
      89             : // The amount of time, in milliseconds, that we will wait for active storage
      90             : // transactions on shutdown before aborting them.
      91             : #define DEFAULT_SHUTDOWN_TIMER_MS 30000
      92             : 
      93             : // Preference that users can set to override temporary storage smart limit
      94             : // calculation.
      95             : #define PREF_FIXED_LIMIT "dom.quotaManager.temporaryStorage.fixedLimit"
      96             : #define PREF_CHUNK_SIZE "dom.quotaManager.temporaryStorage.chunkSize"
      97             : 
      98             : // Preference that is used to enable testing features
      99             : #define PREF_TESTING_FEATURES "dom.quotaManager.testing"
     100             : 
     101             : // profile-before-change, when we need to shut down quota manager
     102             : #define PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID "profile-before-change-qm"
     103             : 
     104             : #define KB * 1024ULL
     105             : #define MB * 1024ULL KB
     106             : #define GB * 1024ULL MB
     107             : 
     108             : namespace mozilla {
     109             : namespace dom {
     110             : namespace quota {
     111             : 
     112             : using namespace mozilla::ipc;
     113             : 
     114             : // We want profiles to be platform-independent so we always need to replace
     115             : // the same characters on every platform. Windows has the most extensive set
     116             : // of illegal characters so we use its FILE_ILLEGAL_CHARACTERS and
     117             : // FILE_PATH_SEPARATOR.
     118             : const char QuotaManager::kReplaceChars[] = CONTROL_CHARACTERS "/:*?\"<>|\\";
     119             : 
     120             : namespace {
     121             : 
     122             : /*******************************************************************************
     123             :  * Constants
     124             :  ******************************************************************************/
     125             : 
     126             : const uint32_t kSQLitePageSizeOverride = 512;
     127             : 
     128             : // Major storage version. Bump for backwards-incompatible changes.
     129             : const uint32_t kMajorStorageVersion = 2;
     130             : 
     131             : // Minor storage version. Bump for backwards-compatible changes.
     132             : const uint32_t kMinorStorageVersion = 0;
     133             : 
     134             : // The storage version we store in the SQLite database is a (signed) 32-bit
     135             : // integer. The major version is left-shifted 16 bits so the max value is
     136             : // 0xFFFF. The minor version occupies the lower 16 bits and its max is 0xFFFF.
     137             : static_assert(kMajorStorageVersion <= 0xFFFF,
     138             :               "Major version needs to fit in 16 bits.");
     139             : static_assert(kMinorStorageVersion <= 0xFFFF,
     140             :               "Minor version needs to fit in 16 bits.");
     141             : 
     142             : const int32_t kStorageVersion =
     143             :   int32_t((kMajorStorageVersion << 16) + kMinorStorageVersion);
     144             : 
     145             : static_assert(
     146             :   static_cast<uint32_t>(StorageType::Persistent) ==
     147             :   static_cast<uint32_t>(PERSISTENCE_TYPE_PERSISTENT),
     148             :   "Enum values should match.");
     149             : 
     150             : static_assert(
     151             :   static_cast<uint32_t>(StorageType::Temporary) ==
     152             :   static_cast<uint32_t>(PERSISTENCE_TYPE_TEMPORARY),
     153             :   "Enum values should match.");
     154             : 
     155             : static_assert(
     156             :   static_cast<uint32_t>(StorageType::Default) ==
     157             :   static_cast<uint32_t>(PERSISTENCE_TYPE_DEFAULT),
     158             :   "Enum values should match.");
     159             : 
     160             : const char kChromeOrigin[] = "chrome";
     161             : const char kAboutHomeOriginPrefix[] = "moz-safe-about:home";
     162             : const char kIndexedDBOriginPrefix[] = "indexeddb://";
     163             : const char kResourceOriginPrefix[] = "resource://";
     164             : 
     165             : #define INDEXEDDB_DIRECTORY_NAME "indexedDB"
     166             : #define STORAGE_DIRECTORY_NAME "storage"
     167             : #define PERSISTENT_DIRECTORY_NAME "persistent"
     168             : #define PERMANENT_DIRECTORY_NAME "permanent"
     169             : #define TEMPORARY_DIRECTORY_NAME "temporary"
     170             : #define DEFAULT_DIRECTORY_NAME "default"
     171             : 
     172             : enum AppId {
     173             :   kNoAppId = nsIScriptSecurityManager::NO_APP_ID,
     174             :   kUnknownAppId = nsIScriptSecurityManager::UNKNOWN_APP_ID
     175             : };
     176             : 
     177             : #define STORAGE_FILE_NAME "storage.sqlite"
     178             : 
     179             : // The name of the file that we use to load/save the last access time of an
     180             : // origin.
     181             : // XXX We should get rid of old metadata files at some point, bug 1343576.
     182             : #define METADATA_FILE_NAME ".metadata"
     183             : #define METADATA_TMP_FILE_NAME ".metadata-tmp"
     184             : #define METADATA_V2_FILE_NAME ".metadata-v2"
     185             : #define METADATA_V2_TMP_FILE_NAME ".metadata-v2-tmp"
     186             : 
     187             : /******************************************************************************
     188             :  * SQLite functions
     189             :  ******************************************************************************/
     190             : 
     191             : int32_t
     192           0 : MakeStorageVersion(uint32_t aMajorStorageVersion,
     193             :                    uint32_t aMinorStorageVersion)
     194             : {
     195           0 :   return int32_t((aMajorStorageVersion << 16) + aMinorStorageVersion);
     196             : }
     197             : 
     198             : uint32_t
     199           0 : GetMajorStorageVersion(int32_t aStorageVersion)
     200             : {
     201           0 :   return uint32_t(aStorageVersion >> 16);
     202             : 
     203             : }
     204             : 
     205             : nsresult
     206           0 : CreateTables(mozIStorageConnection* aConnection)
     207             : {
     208           0 :   AssertIsOnIOThread();
     209           0 :   MOZ_ASSERT(aConnection);
     210             : 
     211             :   // The database doesn't have any tables for now. It's only used for storage
     212             :   // version checking.
     213             :   // However, this is the place where any future tables should be created.
     214             : 
     215             :   nsresult rv;
     216             : 
     217             : #ifdef DEBUG
     218             :   {
     219             :     int32_t storageVersion;
     220           0 :     rv = aConnection->GetSchemaVersion(&storageVersion);
     221           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     222           0 :       return rv;
     223             :     }
     224             : 
     225           0 :     MOZ_ASSERT(storageVersion == 0);
     226             :   }
     227             : #endif
     228             : 
     229           0 :   rv = aConnection->SetSchemaVersion(kStorageVersion);
     230           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     231           0 :     return rv;
     232             :   }
     233             : 
     234           0 :   return NS_OK;
     235             : }
     236             : 
     237             : /******************************************************************************
     238             :  * Quota manager class declarations
     239             :  ******************************************************************************/
     240             : 
     241             : } // namespace
     242             : 
     243             : class DirectoryLockImpl final
     244             :   : public DirectoryLock
     245             : {
     246             :   RefPtr<QuotaManager> mQuotaManager;
     247             : 
     248             :   const Nullable<PersistenceType> mPersistenceType;
     249             :   const nsCString mGroup;
     250             :   const OriginScope mOriginScope;
     251             :   const Nullable<Client::Type> mClientType;
     252             :   RefPtr<OpenDirectoryListener> mOpenListener;
     253             : 
     254             :   nsTArray<DirectoryLockImpl*> mBlocking;
     255             :   nsTArray<DirectoryLockImpl*> mBlockedOn;
     256             : 
     257             :   const bool mExclusive;
     258             : 
     259             :   // Internal quota manager operations use this flag to prevent directory lock
     260             :   // registraction/unregistration from updating origin access time, etc.
     261             :   const bool mInternal;
     262             : 
     263             :   bool mInvalidated;
     264             : 
     265             : public:
     266             :   DirectoryLockImpl(QuotaManager* aQuotaManager,
     267             :                     const Nullable<PersistenceType>& aPersistenceType,
     268             :                     const nsACString& aGroup,
     269             :                     const OriginScope& aOriginScope,
     270             :                     const Nullable<Client::Type>& aClientType,
     271             :                     bool aExclusive,
     272             :                     bool aInternal,
     273             :                     OpenDirectoryListener* aOpenListener);
     274             : 
     275             :   void
     276             :   AssertIsOnOwningThread() const
     277             : #ifdef DEBUG
     278             :   ;
     279             : #else
     280             :   { }
     281             : #endif
     282             : 
     283             :   const Nullable<PersistenceType>&
     284           0 :   GetPersistenceType() const
     285             :   {
     286           0 :     return mPersistenceType;
     287             :   }
     288             : 
     289             :   const nsACString&
     290           0 :   GetGroup() const
     291             :   {
     292           0 :     return mGroup;
     293             :   }
     294             : 
     295             :   const OriginScope&
     296           0 :   GetOriginScope() const
     297             :   {
     298           0 :     return mOriginScope;
     299             :   }
     300             : 
     301             :   const Nullable<Client::Type>&
     302           0 :   GetClientType() const
     303             :   {
     304           0 :     return mClientType;
     305             :   }
     306             : 
     307             :   bool
     308           0 :   IsInternal() const
     309             :   {
     310           0 :     return mInternal;
     311             :   }
     312             : 
     313             :   bool
     314           0 :   ShouldUpdateLockTable()
     315             :   {
     316           0 :     return !mInternal &&
     317           0 :            mPersistenceType.Value() != PERSISTENCE_TYPE_PERSISTENT;
     318             :   }
     319             : 
     320             :   // Test whether this DirectoryLock needs to wait for the given lock.
     321             :   bool
     322             :   MustWaitFor(const DirectoryLockImpl& aLock);
     323             : 
     324             :   void
     325           0 :   AddBlockingLock(DirectoryLockImpl* aLock)
     326             :   {
     327           0 :     AssertIsOnOwningThread();
     328             : 
     329           0 :     mBlocking.AppendElement(aLock);
     330           0 :   }
     331             : 
     332             :   const nsTArray<DirectoryLockImpl*>&
     333           0 :   GetBlockedOnLocks()
     334             :   {
     335           0 :     return mBlockedOn;
     336             :   }
     337             : 
     338             :   void
     339           0 :   AddBlockedOnLock(DirectoryLockImpl* aLock)
     340             :   {
     341           0 :     AssertIsOnOwningThread();
     342             : 
     343           0 :     mBlockedOn.AppendElement(aLock);
     344           0 :   }
     345             : 
     346             :   void
     347           0 :   MaybeUnblock(DirectoryLockImpl* aLock)
     348             :   {
     349           0 :     AssertIsOnOwningThread();
     350             : 
     351           0 :     mBlockedOn.RemoveElement(aLock);
     352           0 :     if (mBlockedOn.IsEmpty()) {
     353           0 :       NotifyOpenListener();
     354             :     }
     355           0 :   }
     356             : 
     357             :   void
     358             :   NotifyOpenListener();
     359             : 
     360             :   void
     361           0 :   Invalidate()
     362             :   {
     363           0 :     AssertIsOnOwningThread();
     364             : 
     365           0 :     mInvalidated = true;
     366           0 :   }
     367             : 
     368           0 :   NS_INLINE_DECL_REFCOUNTING(DirectoryLockImpl)
     369             : 
     370             : private:
     371             :   ~DirectoryLockImpl();
     372             : };
     373             : 
     374             : class QuotaObject::StoragePressureRunnable final
     375             :   : public Runnable
     376             : {
     377             :   const uint64_t mUsage;
     378             : 
     379             : public:
     380           0 :   explicit StoragePressureRunnable(uint64_t aUsage)
     381           0 :     : Runnable("dom::quota::QuotaObject::StoragePressureRunnable")
     382           0 :     , mUsage(aUsage)
     383           0 :   { }
     384             : 
     385             : private:
     386           0 :   ~StoragePressureRunnable()
     387           0 :   { }
     388             : 
     389             :   NS_DECL_NSIRUNNABLE
     390             : };
     391             : 
     392             : class QuotaManager::CreateRunnable final
     393             :   : public BackgroundThreadObject
     394             :   , public Runnable
     395             : {
     396             :   nsTArray<nsCOMPtr<nsIRunnable>> mCallbacks;
     397             :   nsString mBaseDirPath;
     398             :   RefPtr<QuotaManager> mManager;
     399             :   nsresult mResultCode;
     400             : 
     401             :   enum class State
     402             :   {
     403             :     Initial,
     404             :     CreatingManager,
     405             :     RegisteringObserver,
     406             :     CallingCallbacks,
     407             :     Completed
     408             :   };
     409             : 
     410             :   State mState;
     411             : 
     412             : public:
     413           0 :   CreateRunnable()
     414           0 :     : Runnable("dom::quota::QuotaManager::CreateRunnable")
     415             :     , mResultCode(NS_OK)
     416           0 :     , mState(State::Initial)
     417             :   {
     418           0 :     AssertIsOnBackgroundThread();
     419           0 :   }
     420             : 
     421             :   void
     422           0 :   AddCallback(nsIRunnable* aCallback)
     423             :   {
     424           0 :     AssertIsOnOwningThread();
     425           0 :     MOZ_ASSERT(aCallback);
     426             : 
     427           0 :     mCallbacks.AppendElement(aCallback);
     428           0 :   }
     429             : 
     430             : private:
     431           0 :   ~CreateRunnable()
     432           0 :   { }
     433             : 
     434             :   nsresult
     435             :   Init();
     436             : 
     437             :   nsresult
     438             :   CreateManager();
     439             : 
     440             :   nsresult
     441             :   RegisterObserver();
     442             : 
     443             :   void
     444             :   CallCallbacks();
     445             : 
     446             :   State
     447             :   GetNextState(nsCOMPtr<nsIEventTarget>& aThread);
     448             : 
     449             :   NS_DECL_NSIRUNNABLE
     450             : };
     451             : 
     452             : class QuotaManager::ShutdownRunnable final
     453             :   : public Runnable
     454             : {
     455             :   // Only touched on the main thread.
     456             :   bool& mDone;
     457             : 
     458             : public:
     459           0 :   explicit ShutdownRunnable(bool& aDone)
     460           0 :     : Runnable("dom::quota::QuotaManager::ShutdownRunnable")
     461           0 :     , mDone(aDone)
     462             :   {
     463           0 :     MOZ_ASSERT(NS_IsMainThread());
     464           0 :   }
     465             : 
     466             : private:
     467           0 :   ~ShutdownRunnable()
     468           0 :   { }
     469             : 
     470             :   NS_DECL_NSIRUNNABLE
     471             : };
     472             : 
     473             : class QuotaManager::ShutdownObserver final
     474             :   : public nsIObserver
     475             : {
     476             :   nsCOMPtr<nsIEventTarget> mBackgroundThread;
     477             : 
     478             : public:
     479           0 :   explicit ShutdownObserver(nsIEventTarget* aBackgroundThread)
     480           0 :     : mBackgroundThread(aBackgroundThread)
     481             :   {
     482           0 :     MOZ_ASSERT(NS_IsMainThread());
     483           0 :   }
     484             : 
     485             :   NS_DECL_ISUPPORTS
     486             :   NS_DECL_NSIOBSERVER
     487             : 
     488             : private:
     489           0 :   ~ShutdownObserver()
     490           0 :   {
     491           0 :     MOZ_ASSERT(NS_IsMainThread());
     492           0 :   }
     493             : };
     494             : 
     495             : namespace {
     496             : 
     497             : /*******************************************************************************
     498             :  * Local class declarations
     499             :  ******************************************************************************/
     500             : 
     501             : } // namespace
     502             : 
     503             : class OriginInfo final
     504             : {
     505             :   friend class GroupInfo;
     506             :   friend class QuotaManager;
     507             :   friend class QuotaObject;
     508             : 
     509             : public:
     510             :   OriginInfo(GroupInfo* aGroupInfo, const nsACString& aOrigin,
     511             :              uint64_t aUsage, int64_t aAccessTime, bool aPersisted);
     512             : 
     513           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OriginInfo)
     514             : 
     515             :   int64_t
     516           0 :   LockedAccessTime() const
     517             :   {
     518           0 :     AssertCurrentThreadOwnsQuotaMutex();
     519             : 
     520           0 :     return mAccessTime;
     521             :   }
     522             : 
     523             :   bool
     524           0 :   LockedPersisted() const
     525             :   {
     526           0 :     AssertCurrentThreadOwnsQuotaMutex();
     527             : 
     528           0 :     return mPersisted;
     529             :   }
     530             : 
     531             : private:
     532             :   // Private destructor, to discourage deletion outside of Release():
     533           0 :   ~OriginInfo()
     534           0 :   {
     535           0 :     MOZ_COUNT_DTOR(OriginInfo);
     536             : 
     537           0 :     MOZ_ASSERT(!mQuotaObjects.Count());
     538           0 :   }
     539             : 
     540             :   void
     541             :   LockedDecreaseUsage(int64_t aSize);
     542             : 
     543             :   void
     544           0 :   LockedUpdateAccessTime(int64_t aAccessTime)
     545             :   {
     546           0 :     AssertCurrentThreadOwnsQuotaMutex();
     547             : 
     548           0 :     mAccessTime = aAccessTime;
     549           0 :   }
     550             : 
     551             :   void
     552             :   LockedPersist();
     553             : 
     554             :   nsDataHashtable<nsStringHashKey, QuotaObject*> mQuotaObjects;
     555             : 
     556             :   GroupInfo* mGroupInfo;
     557             :   const nsCString mOrigin;
     558             :   uint64_t mUsage;
     559             :   int64_t mAccessTime;
     560             :   bool mPersisted;
     561             : };
     562             : 
     563             : class OriginInfoLRUComparator
     564             : {
     565             : public:
     566             :   bool
     567           0 :   Equals(const OriginInfo* a, const OriginInfo* b) const
     568             :   {
     569           0 :     return a && b ?
     570           0 :              a->LockedAccessTime() == b->LockedAccessTime() :
     571           0 :              !a && !b ? true : false;
     572             :   }
     573             : 
     574             :   bool
     575           0 :   LessThan(const OriginInfo* a, const OriginInfo* b) const
     576             :   {
     577             :     return
     578           0 :       a && b ? a->LockedAccessTime() < b->LockedAccessTime() : b ? true : false;
     579             :   }
     580             : };
     581             : 
     582             : class GroupInfo final
     583             : {
     584             :   friend class GroupInfoPair;
     585             :   friend class OriginInfo;
     586             :   friend class QuotaManager;
     587             :   friend class QuotaObject;
     588             : 
     589             : public:
     590           0 :   GroupInfo(GroupInfoPair* aGroupInfoPair, PersistenceType aPersistenceType,
     591             :             const nsACString& aGroup)
     592           0 :   : mGroupInfoPair(aGroupInfoPair), mPersistenceType(aPersistenceType),
     593           0 :     mGroup(aGroup), mUsage(0)
     594             :   {
     595           0 :     MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
     596             : 
     597           0 :     MOZ_COUNT_CTOR(GroupInfo);
     598           0 :   }
     599             : 
     600           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GroupInfo)
     601             : 
     602             : private:
     603             :   // Private destructor, to discourage deletion outside of Release():
     604           0 :   ~GroupInfo()
     605           0 :   {
     606           0 :     MOZ_COUNT_DTOR(GroupInfo);
     607           0 :   }
     608             : 
     609             :   already_AddRefed<OriginInfo>
     610             :   LockedGetOriginInfo(const nsACString& aOrigin);
     611             : 
     612             :   void
     613             :   LockedAddOriginInfo(OriginInfo* aOriginInfo);
     614             : 
     615             :   void
     616             :   LockedRemoveOriginInfo(const nsACString& aOrigin);
     617             : 
     618             :   void
     619             :   LockedRemoveOriginInfos();
     620             : 
     621             :   bool
     622           0 :   LockedHasOriginInfos()
     623             :   {
     624           0 :     AssertCurrentThreadOwnsQuotaMutex();
     625             : 
     626           0 :     return !mOriginInfos.IsEmpty();
     627             :   }
     628             : 
     629             :   nsTArray<RefPtr<OriginInfo> > mOriginInfos;
     630             : 
     631             :   GroupInfoPair* mGroupInfoPair;
     632             :   PersistenceType mPersistenceType;
     633             :   nsCString mGroup;
     634             :   uint64_t mUsage;
     635             : };
     636             : 
     637             : class GroupInfoPair
     638             : {
     639             :   friend class QuotaManager;
     640             :   friend class QuotaObject;
     641             : 
     642             : public:
     643           0 :   GroupInfoPair()
     644           0 :   {
     645           0 :     MOZ_COUNT_CTOR(GroupInfoPair);
     646           0 :   }
     647             : 
     648           0 :   ~GroupInfoPair()
     649           0 :   {
     650           0 :     MOZ_COUNT_DTOR(GroupInfoPair);
     651           0 :   }
     652             : 
     653             : private:
     654             :   already_AddRefed<GroupInfo>
     655           0 :   LockedGetGroupInfo(PersistenceType aPersistenceType)
     656             :   {
     657           0 :     AssertCurrentThreadOwnsQuotaMutex();
     658           0 :     MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
     659             : 
     660             :     RefPtr<GroupInfo> groupInfo =
     661           0 :       GetGroupInfoForPersistenceType(aPersistenceType);
     662           0 :     return groupInfo.forget();
     663             :   }
     664             : 
     665             :   void
     666           0 :   LockedSetGroupInfo(PersistenceType aPersistenceType, GroupInfo* aGroupInfo)
     667             :   {
     668           0 :     AssertCurrentThreadOwnsQuotaMutex();
     669           0 :     MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
     670             : 
     671             :     RefPtr<GroupInfo>& groupInfo =
     672           0 :       GetGroupInfoForPersistenceType(aPersistenceType);
     673           0 :     groupInfo = aGroupInfo;
     674           0 :   }
     675             : 
     676             :   void
     677           0 :   LockedClearGroupInfo(PersistenceType aPersistenceType)
     678             :   {
     679           0 :     AssertCurrentThreadOwnsQuotaMutex();
     680           0 :     MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
     681             : 
     682             :     RefPtr<GroupInfo>& groupInfo =
     683           0 :       GetGroupInfoForPersistenceType(aPersistenceType);
     684           0 :     groupInfo = nullptr;
     685           0 :   }
     686             : 
     687             :   bool
     688           0 :   LockedHasGroupInfos()
     689             :   {
     690           0 :     AssertCurrentThreadOwnsQuotaMutex();
     691             : 
     692           0 :     return mTemporaryStorageGroupInfo || mDefaultStorageGroupInfo;
     693             :   }
     694             : 
     695             :   RefPtr<GroupInfo>&
     696             :   GetGroupInfoForPersistenceType(PersistenceType aPersistenceType);
     697             : 
     698             :   RefPtr<GroupInfo> mTemporaryStorageGroupInfo;
     699             :   RefPtr<GroupInfo> mDefaultStorageGroupInfo;
     700             : };
     701             : 
     702             : namespace {
     703             : 
     704             : class CollectOriginsHelper final
     705             :   : public Runnable
     706             : {
     707             :   uint64_t mMinSizeToBeFreed;
     708             : 
     709             :   Mutex& mMutex;
     710             :   CondVar mCondVar;
     711             : 
     712             :   // The members below are protected by mMutex.
     713             :   nsTArray<RefPtr<DirectoryLockImpl>> mLocks;
     714             :   uint64_t mSizeToBeFreed;
     715             :   bool mWaiting;
     716             : 
     717             : public:
     718             :   CollectOriginsHelper(mozilla::Mutex& aMutex,
     719             :                        uint64_t aMinSizeToBeFreed);
     720             : 
     721             :   // Blocks the current thread until origins are collected on the main thread.
     722             :   // The returned value contains an aggregate size of those origins.
     723             :   int64_t
     724             :   BlockAndReturnOriginsForEviction(
     725             :                                  nsTArray<RefPtr<DirectoryLockImpl>>& aLocks);
     726             : 
     727             : private:
     728           0 :   ~CollectOriginsHelper()
     729           0 :   { }
     730             : 
     731             :   NS_IMETHOD
     732             :   Run() override;
     733             : };
     734             : 
     735             : class OriginOperationBase
     736             :   : public BackgroundThreadObject
     737             :   , public Runnable
     738             : {
     739             : protected:
     740             :   nsresult mResultCode;
     741             : 
     742             :   enum State {
     743             :     // Not yet run.
     744             :     State_Initial,
     745             : 
     746             :     // Running initialization on the main thread.
     747             :     State_Initializing,
     748             : 
     749             :     // Running initialization on the owning thread.
     750             :     State_FinishingInit,
     751             : 
     752             :     // Running quota manager initialization on the owning thread.
     753             :     State_CreatingQuotaManager,
     754             : 
     755             :     // Running on the owning thread in the listener for OpenDirectory.
     756             :     State_DirectoryOpenPending,
     757             : 
     758             :     // Running on the IO thread.
     759             :     State_DirectoryWorkOpen,
     760             : 
     761             :     // Running on the owning thread after all work is done.
     762             :     State_UnblockingOpen,
     763             : 
     764             :     // All done.
     765             :     State_Complete
     766             :   };
     767             : 
     768             : private:
     769             :   State mState;
     770             :   bool mActorDestroyed;
     771             : 
     772             : protected:
     773             :   bool mNeedsMainThreadInit;
     774             :   bool mNeedsQuotaManagerInit;
     775             : 
     776             : public:
     777             :   void
     778           0 :   NoteActorDestroyed()
     779             :   {
     780           0 :     AssertIsOnOwningThread();
     781             : 
     782           0 :     mActorDestroyed = true;
     783           0 :   }
     784             : 
     785             :   bool
     786           0 :   IsActorDestroyed() const
     787             :   {
     788           0 :     AssertIsOnOwningThread();
     789             : 
     790           0 :     return mActorDestroyed;
     791             :   }
     792             : 
     793             : protected:
     794           0 :   explicit OriginOperationBase(
     795             :         nsIEventTarget* aOwningThread = GetCurrentThreadEventTarget())
     796           0 :     : BackgroundThreadObject(aOwningThread)
     797             :     , Runnable("dom::quota::OriginOperationBase")
     798             :     , mResultCode(NS_OK)
     799             :     , mState(State_Initial)
     800             :     , mActorDestroyed(false)
     801             :     , mNeedsMainThreadInit(false)
     802           0 :     , mNeedsQuotaManagerInit(false)
     803           0 :   { }
     804             : 
     805             :   // Reference counted.
     806           0 :   virtual ~OriginOperationBase()
     807           0 :   {
     808           0 :     MOZ_ASSERT(mState == State_Complete);
     809           0 :     MOZ_ASSERT(mActorDestroyed);
     810           0 :   }
     811             : 
     812             : #ifdef DEBUG
     813             :   State
     814           0 :   GetState() const
     815             :   {
     816           0 :     return mState;
     817             :   }
     818             : #endif
     819             : 
     820             :   void
     821           0 :   SetState(State aState)
     822             :   {
     823           0 :     MOZ_ASSERT(mState == State_Initial);
     824           0 :     mState = aState;
     825           0 :   }
     826             : 
     827             :   void
     828           0 :   AdvanceState()
     829             :   {
     830           0 :     switch (mState) {
     831             :       case State_Initial:
     832           0 :         mState = State_Initializing;
     833           0 :         return;
     834             :       case State_Initializing:
     835           0 :         mState = State_FinishingInit;
     836           0 :         return;
     837             :       case State_FinishingInit:
     838           0 :         mState = State_CreatingQuotaManager;
     839           0 :         return;
     840             :       case State_CreatingQuotaManager:
     841           0 :         mState = State_DirectoryOpenPending;
     842           0 :         return;
     843             :       case State_DirectoryOpenPending:
     844           0 :         mState = State_DirectoryWorkOpen;
     845           0 :         return;
     846             :       case State_DirectoryWorkOpen:
     847           0 :         mState = State_UnblockingOpen;
     848           0 :         return;
     849             :       case State_UnblockingOpen:
     850           0 :         mState = State_Complete;
     851           0 :         return;
     852             :       default:
     853           0 :         MOZ_CRASH("Bad state!");
     854             :     }
     855             :   }
     856             : 
     857             :   NS_IMETHOD
     858             :   Run() override;
     859             : 
     860             :   virtual nsresult
     861           0 :   DoInitOnMainThread()
     862             :   {
     863           0 :     return NS_OK;
     864             :   }
     865             : 
     866             :   virtual void
     867             :   Open() = 0;
     868             : 
     869             :   nsresult
     870             :   DirectoryOpen();
     871             : 
     872             :   virtual nsresult
     873             :   DoDirectoryWork(QuotaManager* aQuotaManager) = 0;
     874             : 
     875             :   void
     876             :   Finish(nsresult aResult);
     877             : 
     878             :   virtual void
     879             :   UnblockOpen() = 0;
     880             : 
     881             : private:
     882             :   nsresult
     883             :   Init();
     884             : 
     885             :   nsresult
     886             :   InitOnMainThread();
     887             : 
     888             :   nsresult
     889             :   FinishInit();
     890             : 
     891             :   nsresult
     892             :   QuotaManagerOpen();
     893             : 
     894             :   nsresult
     895             :   DirectoryWork();
     896             : };
     897             : 
     898             : class FinalizeOriginEvictionOp
     899             :   : public OriginOperationBase
     900             : {
     901             :   nsTArray<RefPtr<DirectoryLockImpl>> mLocks;
     902             : 
     903             : public:
     904           0 :   FinalizeOriginEvictionOp(nsIEventTarget* aBackgroundThread,
     905             :                            nsTArray<RefPtr<DirectoryLockImpl>>& aLocks)
     906           0 :     : OriginOperationBase(aBackgroundThread)
     907             :   {
     908           0 :     MOZ_ASSERT(!NS_IsMainThread());
     909             : 
     910           0 :     mLocks.SwapElements(aLocks);
     911           0 :   }
     912             : 
     913             :   void
     914             :   Dispatch();
     915             : 
     916             :   void
     917             :   RunOnIOThreadImmediately();
     918             : 
     919             : private:
     920           0 :   ~FinalizeOriginEvictionOp()
     921           0 :   { }
     922             : 
     923             :   virtual void
     924             :   Open() override;
     925             : 
     926             :   virtual nsresult
     927             :   DoDirectoryWork(QuotaManager* aQuotaManager) override;
     928             : 
     929             :   virtual void
     930             :   UnblockOpen() override;
     931             : };
     932             : 
     933             : class NormalOriginOperationBase
     934             :   : public OriginOperationBase
     935             :   , public OpenDirectoryListener
     936             : {
     937             :   RefPtr<DirectoryLock> mDirectoryLock;
     938             : 
     939             : protected:
     940             :   Nullable<PersistenceType> mPersistenceType;
     941             :   OriginScope mOriginScope;
     942             :   mozilla::Atomic<bool> mCanceled;
     943             :   const bool mExclusive;
     944             : 
     945             : public:
     946             :   void
     947           0 :   RunImmediately()
     948             :   {
     949           0 :     MOZ_ASSERT(GetState() == State_Initial);
     950             : 
     951           0 :     MOZ_ALWAYS_SUCCEEDS(this->Run());
     952           0 :   }
     953             : 
     954             : protected:
     955           0 :   NormalOriginOperationBase(const Nullable<PersistenceType>& aPersistenceType,
     956             :                             const OriginScope& aOriginScope,
     957             :                             bool aExclusive)
     958           0 :     : mPersistenceType(aPersistenceType)
     959             :     , mOriginScope(aOriginScope)
     960           0 :     , mExclusive(aExclusive)
     961             :   {
     962           0 :     AssertIsOnOwningThread();
     963           0 :   }
     964             : 
     965           0 :   ~NormalOriginOperationBase()
     966           0 :   { }
     967             : 
     968             : private:
     969             :   NS_DECL_ISUPPORTS_INHERITED
     970             : 
     971             :   virtual void
     972             :   Open() override;
     973             : 
     974             :   virtual void
     975             :   UnblockOpen() override;
     976             : 
     977             :   // OpenDirectoryListener overrides.
     978             :   virtual void
     979             :   DirectoryLockAcquired(DirectoryLock* aLock) override;
     980             : 
     981             :   virtual void
     982             :   DirectoryLockFailed() override;
     983             : 
     984             :   // Used to send results before unblocking open.
     985             :   virtual void
     986             :   SendResults() = 0;
     987             : };
     988             : 
     989             : class SaveOriginAccessTimeOp
     990             :   : public NormalOriginOperationBase
     991             : {
     992             :   int64_t mTimestamp;
     993             : 
     994             : public:
     995           0 :   SaveOriginAccessTimeOp(PersistenceType aPersistenceType,
     996             :                          const nsACString& aOrigin,
     997             :                          int64_t aTimestamp)
     998           0 :     : NormalOriginOperationBase(Nullable<PersistenceType>(aPersistenceType),
     999           0 :                                 OriginScope::FromOrigin(aOrigin),
    1000             :                                 /* aExclusive */ false)
    1001           0 :     , mTimestamp(aTimestamp)
    1002             :   {
    1003           0 :     AssertIsOnOwningThread();
    1004           0 :   }
    1005             : 
    1006             : private:
    1007           0 :   ~SaveOriginAccessTimeOp()
    1008           0 :   { }
    1009             : 
    1010             :   virtual nsresult
    1011             :   DoDirectoryWork(QuotaManager* aQuotaManager) override;
    1012             : 
    1013             :   virtual void
    1014             :   SendResults() override;
    1015             : };
    1016             : 
    1017             : /*******************************************************************************
    1018             :  * Actor class declarations
    1019             :  ******************************************************************************/
    1020             : 
    1021             : class Quota final
    1022             :   : public PQuotaParent
    1023             : {
    1024             : #ifdef DEBUG
    1025             :   bool mActorDestroyed;
    1026             : #endif
    1027             : 
    1028             : public:
    1029             :   Quota();
    1030             : 
    1031           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::quota::Quota)
    1032             : 
    1033             : private:
    1034             :   ~Quota();
    1035             : 
    1036             :   void
    1037             :   StartIdleMaintenance();
    1038             : 
    1039             :   // IPDL methods.
    1040             :   virtual void
    1041             :   ActorDestroy(ActorDestroyReason aWhy) override;
    1042             : 
    1043             :   virtual PQuotaUsageRequestParent*
    1044             :   AllocPQuotaUsageRequestParent(const UsageRequestParams& aParams) override;
    1045             : 
    1046             :   virtual mozilla::ipc::IPCResult
    1047             :   RecvPQuotaUsageRequestConstructor(PQuotaUsageRequestParent* aActor,
    1048             :                                     const UsageRequestParams& aParams) override;
    1049             : 
    1050             :   virtual bool
    1051             :   DeallocPQuotaUsageRequestParent(PQuotaUsageRequestParent* aActor) override;
    1052             : 
    1053             :   virtual PQuotaRequestParent*
    1054             :   AllocPQuotaRequestParent(const RequestParams& aParams) override;
    1055             : 
    1056             :   virtual mozilla::ipc::IPCResult
    1057             :   RecvPQuotaRequestConstructor(PQuotaRequestParent* aActor,
    1058             :                                const RequestParams& aParams) override;
    1059             : 
    1060             :   virtual bool
    1061             :   DeallocPQuotaRequestParent(PQuotaRequestParent* aActor) override;
    1062             : 
    1063             :   virtual mozilla::ipc::IPCResult
    1064             :   RecvStartIdleMaintenance() override;
    1065             : 
    1066             :   virtual mozilla::ipc::IPCResult
    1067             :   RecvStopIdleMaintenance() override;
    1068             : };
    1069             : 
    1070           0 : class QuotaUsageRequestBase
    1071             :   : public NormalOriginOperationBase
    1072             :   , public PQuotaUsageRequestParent
    1073             : {
    1074             : public:
    1075             :   // May be overridden by subclasses if they need to perform work on the
    1076             :   // background thread before being run.
    1077             :   virtual bool
    1078             :   Init(Quota* aQuota);
    1079             : 
    1080             : protected:
    1081           0 :   QuotaUsageRequestBase()
    1082           0 :     : NormalOriginOperationBase(Nullable<PersistenceType>(),
    1083           0 :                                 OriginScope::FromNull(),
    1084           0 :                                 /* aExclusive */ false)
    1085           0 :   { }
    1086             : 
    1087             :   nsresult
    1088             :   GetUsageForOrigin(QuotaManager* aQuotaManager,
    1089             :                     PersistenceType aPersistenceType,
    1090             :                     const nsACString& aGroup,
    1091             :                     const nsACString& aOrigin,
    1092             :                     UsageInfo* aUsageInfo);
    1093             : 
    1094             :   // Subclasses use this override to set the IPDL response value.
    1095             :   virtual void
    1096             :   GetResponse(UsageRequestResponse& aResponse) = 0;
    1097             : 
    1098             : private:
    1099             :   void
    1100             :   SendResults() override;
    1101             : 
    1102             :   // IPDL methods.
    1103             :   void
    1104             :   ActorDestroy(ActorDestroyReason aWhy) override;
    1105             : 
    1106             :   mozilla::ipc::IPCResult
    1107             :   RecvCancel() override;
    1108             : };
    1109             : 
    1110             : class GetUsageOp final
    1111             :   : public QuotaUsageRequestBase
    1112             : {
    1113             :   nsTArray<OriginUsage> mOriginUsages;
    1114             :   nsDataHashtable<nsCStringHashKey, uint32_t> mOriginUsagesIndex;
    1115             : 
    1116             :   bool mGetAll;
    1117             : 
    1118             : public:
    1119             :   explicit GetUsageOp(const UsageRequestParams& aParams);
    1120             : 
    1121             : private:
    1122           0 :   ~GetUsageOp()
    1123           0 :   { }
    1124             : 
    1125             :   nsresult
    1126             :   TraverseRepository(QuotaManager* aQuotaManager,
    1127             :                      PersistenceType aPersistenceType);
    1128             : 
    1129             :   nsresult
    1130             :   DoDirectoryWork(QuotaManager* aQuotaManager) override;
    1131             : 
    1132             :   void
    1133             :   GetResponse(UsageRequestResponse& aResponse) override;
    1134             : };
    1135             : 
    1136             : class GetOriginUsageOp final
    1137             :   : public QuotaUsageRequestBase
    1138             : {
    1139             :   // If mGetGroupUsage is false, we use mUsageInfo to record the origin usage
    1140             :   // and the file usage. Otherwise, we use it to record the group usage and the
    1141             :   // limit.
    1142             :   UsageInfo mUsageInfo;
    1143             : 
    1144             :   const OriginUsageParams mParams;
    1145             :   nsCString mSuffix;
    1146             :   nsCString mGroup;
    1147             :   bool mGetGroupUsage;
    1148             : 
    1149             : public:
    1150             :   explicit GetOriginUsageOp(const UsageRequestParams& aParams);
    1151             : 
    1152             :   MOZ_IS_CLASS_INIT bool
    1153             :   Init(Quota* aQuota) override;
    1154             : 
    1155             : private:
    1156           0 :   ~GetOriginUsageOp()
    1157           0 :   { }
    1158             : 
    1159             :   MOZ_IS_CLASS_INIT virtual nsresult
    1160             :   DoInitOnMainThread() override;
    1161             : 
    1162             :   virtual nsresult
    1163             :   DoDirectoryWork(QuotaManager* aQuotaManager) override;
    1164             : 
    1165             :   void
    1166             :   GetResponse(UsageRequestResponse& aResponse) override;
    1167             : };
    1168             : 
    1169           0 : class QuotaRequestBase
    1170             :   : public NormalOriginOperationBase
    1171             :   , public PQuotaRequestParent
    1172             : {
    1173             : public:
    1174             :   // May be overridden by subclasses if they need to perform work on the
    1175             :   // background thread before being run.
    1176             :   virtual bool
    1177             :   Init(Quota* aQuota);
    1178             : 
    1179             : protected:
    1180           0 :   explicit QuotaRequestBase(bool aExclusive)
    1181           0 :     : NormalOriginOperationBase(Nullable<PersistenceType>(),
    1182           0 :                                 OriginScope::FromNull(),
    1183           0 :                                 aExclusive)
    1184           0 :   { }
    1185             : 
    1186             :   // Subclasses use this override to set the IPDL response value.
    1187             :   virtual void
    1188             :   GetResponse(RequestResponse& aResponse) = 0;
    1189             : 
    1190             : private:
    1191             :   virtual void
    1192             :   SendResults() override;
    1193             : 
    1194             :   // IPDL methods.
    1195             :   virtual void
    1196             :   ActorDestroy(ActorDestroyReason aWhy) override;
    1197             : };
    1198             : 
    1199             : class InitOp final
    1200             :   : public QuotaRequestBase
    1201             : {
    1202             : public:
    1203           0 :   InitOp()
    1204           0 :     : QuotaRequestBase(/* aExclusive */ false)
    1205             :   {
    1206           0 :     AssertIsOnOwningThread();
    1207           0 :   }
    1208             : 
    1209             : private:
    1210           0 :   ~InitOp()
    1211           0 :   { }
    1212             : 
    1213             :   nsresult
    1214             :   DoDirectoryWork(QuotaManager* aQuotaManager) override;
    1215             : 
    1216             :   void
    1217             :   GetResponse(RequestResponse& aResponse) override;
    1218             : };
    1219             : 
    1220             : class InitOriginOp final
    1221             :   : public QuotaRequestBase
    1222             : {
    1223             :   const InitOriginParams mParams;
    1224             :   nsCString mSuffix;
    1225             :   nsCString mGroup;
    1226             :   bool mCreated;
    1227             : 
    1228             : public:
    1229             :   explicit InitOriginOp(const RequestParams& aParams);
    1230             : 
    1231             :   bool
    1232             :   Init(Quota* aQuota) override;
    1233             : 
    1234             : private:
    1235           0 :   ~InitOriginOp()
    1236           0 :   { }
    1237             : 
    1238             :   nsresult
    1239             :   DoInitOnMainThread() override;
    1240             : 
    1241             :   nsresult
    1242             :   DoDirectoryWork(QuotaManager* aQuotaManager) override;
    1243             : 
    1244             :   void
    1245             :   GetResponse(RequestResponse& aResponse) override;
    1246             : };
    1247             : 
    1248             : class ResetOrClearOp final
    1249             :   : public QuotaRequestBase
    1250             : {
    1251             :   const bool mClear;
    1252             : 
    1253             : public:
    1254           0 :   explicit ResetOrClearOp(bool aClear)
    1255           0 :     : QuotaRequestBase(/* aExclusive */ true)
    1256           0 :     , mClear(aClear)
    1257             :   {
    1258           0 :     AssertIsOnOwningThread();
    1259           0 :   }
    1260             : 
    1261             : private:
    1262           0 :   ~ResetOrClearOp()
    1263           0 :   { }
    1264             : 
    1265             :   void
    1266             :   DeleteFiles(QuotaManager* aQuotaManager);
    1267             : 
    1268             :   virtual nsresult
    1269             :   DoDirectoryWork(QuotaManager* aQuotaManager) override;
    1270             : 
    1271             :   virtual void
    1272             :   GetResponse(RequestResponse& aResponse) override;
    1273             : };
    1274             : 
    1275           0 : class ClearRequestBase
    1276             :   : public QuotaRequestBase
    1277             : {
    1278             : protected:
    1279           0 :   explicit ClearRequestBase(bool aExclusive)
    1280           0 :     : QuotaRequestBase(aExclusive)
    1281             :   {
    1282           0 :     AssertIsOnOwningThread();
    1283           0 :   }
    1284             : 
    1285             :   void
    1286             :   DeleteFiles(QuotaManager* aQuotaManager,
    1287             :               PersistenceType aPersistenceType);
    1288             : 
    1289             :   nsresult
    1290             :   DoDirectoryWork(QuotaManager* aQuotaManager) override;
    1291             : };
    1292             : 
    1293             : class ClearOriginOp final
    1294             :   : public ClearRequestBase
    1295             : {
    1296             :   const ClearOriginParams mParams;
    1297             : 
    1298             : public:
    1299             :   explicit ClearOriginOp(const RequestParams& aParams);
    1300             : 
    1301             :   bool
    1302             :   Init(Quota* aQuota) override;
    1303             : 
    1304             : private:
    1305           0 :   ~ClearOriginOp()
    1306           0 :   { }
    1307             : 
    1308             :   nsresult
    1309             :   DoInitOnMainThread() override;
    1310             : 
    1311             :   void
    1312             :   GetResponse(RequestResponse& aResponse) override;
    1313             : };
    1314             : 
    1315             : class ClearDataOp final
    1316             :   : public ClearRequestBase
    1317             : {
    1318             :   const ClearDataParams mParams;
    1319             : 
    1320             : public:
    1321             :   explicit ClearDataOp(const RequestParams& aParams);
    1322             : 
    1323             :   bool
    1324             :   Init(Quota* aQuota) override;
    1325             : 
    1326             : private:
    1327           0 :   ~ClearDataOp()
    1328           0 :   { }
    1329             : 
    1330             :   nsresult
    1331             :   DoInitOnMainThread() override;
    1332             : 
    1333             :   void
    1334             :   GetResponse(RequestResponse& aResponse) override;
    1335             : };
    1336             : 
    1337           0 : class PersistRequestBase
    1338             :   : public QuotaRequestBase
    1339             : {
    1340             :   const PrincipalInfo mPrincipalInfo;
    1341             : 
    1342             : protected:
    1343             :   nsCString mSuffix;
    1344             :   nsCString mGroup;
    1345             : 
    1346             : public:
    1347             :   bool
    1348             :   Init(Quota* aQuota) override;
    1349             : 
    1350             : protected:
    1351             :   explicit PersistRequestBase(const PrincipalInfo& aPrincipalInfo);
    1352             : 
    1353             : private:
    1354             :   nsresult
    1355             :   DoInitOnMainThread() override;
    1356             : };
    1357             : 
    1358             : class PersistedOp final
    1359             :   : public PersistRequestBase
    1360             : {
    1361             :   bool mPersisted;
    1362             : 
    1363             : public:
    1364             :   explicit PersistedOp(const RequestParams& aParams);
    1365             : 
    1366             : private:
    1367           0 :   ~PersistedOp()
    1368           0 :   { }
    1369             : 
    1370             :   nsresult
    1371             :   DoDirectoryWork(QuotaManager* aQuotaManager) override;
    1372             : 
    1373             :   void
    1374             :   GetResponse(RequestResponse& aResponse) override;
    1375             : };
    1376             : 
    1377             : class PersistOp final
    1378             :   : public PersistRequestBase
    1379             : {
    1380             : public:
    1381             :   explicit PersistOp(const RequestParams& aParams);
    1382             : 
    1383             : private:
    1384           0 :   ~PersistOp()
    1385           0 :   { }
    1386             : 
    1387             :   nsresult
    1388             :   DoDirectoryWork(QuotaManager* aQuotaManager) override;
    1389             : 
    1390             :   void
    1391             :   GetResponse(RequestResponse& aResponse) override;
    1392             : };
    1393             : 
    1394             : /*******************************************************************************
    1395             :  * Helper Functions
    1396             :  ******************************************************************************/
    1397             : 
    1398             : template <typename T, bool = mozilla::IsUnsigned<T>::value>
    1399             : struct IntChecker
    1400             : {
    1401             :   static void
    1402           0 :   Assert(T aInt)
    1403             :   {
    1404             :     static_assert(mozilla::IsIntegral<T>::value, "Not an integer!");
    1405           0 :     MOZ_ASSERT(aInt >= 0);
    1406           0 :   }
    1407             : };
    1408             : 
    1409             : template <typename T>
    1410             : struct IntChecker<T, true>
    1411             : {
    1412             :   static void
    1413           0 :   Assert(T aInt)
    1414             :   {
    1415             :     static_assert(mozilla::IsIntegral<T>::value, "Not an integer!");
    1416           0 :   }
    1417             : };
    1418             : 
    1419             : template <typename T>
    1420             : void
    1421           0 : AssertNoOverflow(uint64_t aDest, T aArg)
    1422             : {
    1423           0 :   IntChecker<T>::Assert(aDest);
    1424           0 :   IntChecker<T>::Assert(aArg);
    1425           0 :   MOZ_ASSERT(UINT64_MAX - aDest >= uint64_t(aArg));
    1426           0 : }
    1427             : 
    1428             : template <typename T, typename U>
    1429             : void
    1430           0 : AssertNoUnderflow(T aDest, U aArg)
    1431             : {
    1432           0 :   IntChecker<T>::Assert(aDest);
    1433           0 :   IntChecker<T>::Assert(aArg);
    1434           0 :   MOZ_ASSERT(uint64_t(aDest) >= uint64_t(aArg));
    1435           0 : }
    1436             : 
    1437             : bool
    1438           0 : IsOSMetadata(const nsAString& aFileName)
    1439             : {
    1440           0 :   return aFileName.EqualsLiteral(DSSTORE_FILE_NAME);
    1441             : }
    1442             : 
    1443             : bool
    1444           0 : IsOriginMetadata(const nsAString& aFileName)
    1445             : {
    1446           0 :   return aFileName.EqualsLiteral(METADATA_FILE_NAME) ||
    1447           0 :          aFileName.EqualsLiteral(METADATA_V2_FILE_NAME) ||
    1448           0 :          IsOSMetadata(aFileName);
    1449             : }
    1450             : 
    1451             : bool
    1452           0 : IsTempMetadata(const nsAString& aFileName)
    1453             : {
    1454           0 :   return aFileName.EqualsLiteral(METADATA_TMP_FILE_NAME) ||
    1455           0 :          aFileName.EqualsLiteral(METADATA_V2_TMP_FILE_NAME);
    1456             : }
    1457             : 
    1458             : } // namespace
    1459             : 
    1460           0 : BackgroundThreadObject::BackgroundThreadObject()
    1461           0 :   : mOwningThread(GetCurrentThreadEventTarget())
    1462             : {
    1463           0 :   AssertIsOnOwningThread();
    1464           0 : }
    1465             : 
    1466           0 : BackgroundThreadObject::BackgroundThreadObject(nsIEventTarget* aOwningThread)
    1467           0 :   : mOwningThread(aOwningThread)
    1468             : {
    1469           0 : }
    1470             : 
    1471             : #ifdef DEBUG
    1472             : 
    1473             : void
    1474           0 : BackgroundThreadObject::AssertIsOnOwningThread() const
    1475             : {
    1476           0 :   AssertIsOnBackgroundThread();
    1477           0 :   MOZ_ASSERT(mOwningThread);
    1478             :   bool current;
    1479           0 :   MOZ_ASSERT(NS_SUCCEEDED(mOwningThread->IsOnCurrentThread(&current)));
    1480           0 :   MOZ_ASSERT(current);
    1481           0 : }
    1482             : 
    1483             : #endif // DEBUG
    1484             : 
    1485             : nsIEventTarget*
    1486           0 : BackgroundThreadObject::OwningThread() const
    1487             : {
    1488           0 :   MOZ_ASSERT(mOwningThread);
    1489           0 :   return mOwningThread;
    1490             : }
    1491             : 
    1492             : bool
    1493           0 : IsOnIOThread()
    1494             : {
    1495           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    1496           0 :   NS_ASSERTION(quotaManager, "Must have a manager here!");
    1497             : 
    1498             :   bool currentThread;
    1499           0 :   return NS_SUCCEEDED(quotaManager->IOThread()->
    1500           0 :                       IsOnCurrentThread(&currentThread)) && currentThread;
    1501             : }
    1502             : 
    1503             : void
    1504           0 : AssertIsOnIOThread()
    1505             : {
    1506           0 :   NS_ASSERTION(IsOnIOThread(), "Running on the wrong thread!");
    1507           0 : }
    1508             : 
    1509             : void
    1510           0 : AssertCurrentThreadOwnsQuotaMutex()
    1511             : {
    1512             : #ifdef DEBUG
    1513           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    1514           0 :   NS_ASSERTION(quotaManager, "Must have a manager here!");
    1515             : 
    1516           0 :   quotaManager->AssertCurrentThreadOwnsQuotaMutex();
    1517             : #endif
    1518           0 : }
    1519             : 
    1520             : void
    1521           0 : ReportInternalError(const char* aFile, uint32_t aLine, const char* aStr)
    1522             : {
    1523             :   // Get leaf of file path
    1524           0 :   for (const char* p = aFile; *p; ++p) {
    1525           0 :     if (*p == '/' && *(p + 1)) {
    1526           0 :       aFile = p + 1;
    1527             :     }
    1528             :   }
    1529             : 
    1530             :   nsContentUtils::LogSimpleConsoleError(
    1531           0 :     NS_ConvertUTF8toUTF16(nsPrintfCString(
    1532             :                           "Quota %s: %s:%" PRIu32, aStr, aFile, aLine)),
    1533           0 :     "quota");
    1534           0 : }
    1535             : 
    1536             : namespace {
    1537             : 
    1538           3 : StaticRefPtr<QuotaManager> gInstance;
    1539             : bool gCreateFailed = false;
    1540           3 : StaticRefPtr<QuotaManager::CreateRunnable> gCreateRunnable;
    1541             : mozilla::Atomic<bool> gShutdown(false);
    1542             : 
    1543             : // Constants for temporary storage limit computing.
    1544             : static const int32_t kDefaultFixedLimitKB = -1;
    1545             : static const uint32_t kDefaultChunkSizeKB = 10 * 1024;
    1546             : int32_t gFixedLimitKB = kDefaultFixedLimitKB;
    1547             : uint32_t gChunkSizeKB = kDefaultChunkSizeKB;
    1548             : 
    1549             : bool gTestingEnabled = false;
    1550             : 
    1551             : class StorageDirectoryHelper
    1552             :   : public Runnable
    1553             : {
    1554             :   mozilla::Mutex mMutex;
    1555             :   mozilla::CondVar mCondVar;
    1556             :   nsresult mMainThreadResultCode;
    1557             :   bool mWaiting;
    1558             : 
    1559             : protected:
    1560             :   struct OriginProps;
    1561             : 
    1562             :   nsTArray<OriginProps> mOriginProps;
    1563             : 
    1564             :   nsCOMPtr<nsIFile> mDirectory;
    1565             : 
    1566             :   const bool mPersistent;
    1567             : 
    1568             : public:
    1569           0 :   StorageDirectoryHelper(nsIFile* aDirectory, bool aPersistent)
    1570           0 :     : Runnable("dom::quota::StorageDirectoryHelper")
    1571             :     , mMutex("StorageDirectoryHelper::mMutex")
    1572             :     , mCondVar(mMutex, "StorageDirectoryHelper::mCondVar")
    1573             :     , mMainThreadResultCode(NS_OK)
    1574             :     , mWaiting(true)
    1575             :     , mDirectory(aDirectory)
    1576           0 :     , mPersistent(aPersistent)
    1577             :   {
    1578           0 :     AssertIsOnIOThread();
    1579           0 :   }
    1580             : 
    1581             : protected:
    1582           0 :   ~StorageDirectoryHelper()
    1583           0 :   { }
    1584             : 
    1585             :   nsresult
    1586             :   GetDirectoryMetadata(nsIFile* aDirectory,
    1587             :                        int64_t& aTimestamp,
    1588             :                        nsACString& aGroup,
    1589             :                        nsACString& aOrigin,
    1590             :                        Nullable<bool>& aIsApp);
    1591             : 
    1592             :   // Upgrade helper to load the contents of ".metadata-v2" files from previous
    1593             :   // schema versions.  Although QuotaManager has a similar GetDirectoryMetadata2
    1594             :   // method, it is only intended to read current version ".metadata-v2" files.
    1595             :   // And unlike the old ".metadata" files, the ".metadata-v2" format can evolve
    1596             :   // because our "storage.sqlite" lets us track the overall version of the
    1597             :   // storage directory.
    1598             :   nsresult
    1599             :   GetDirectoryMetadata2(nsIFile* aDirectory,
    1600             :                         int64_t& aTimestamp,
    1601             :                         nsACString& aSuffix,
    1602             :                         nsACString& aGroup,
    1603             :                         nsACString& aOrigin,
    1604             :                         bool& aIsApp);
    1605             : 
    1606             :   nsresult
    1607             :   RemoveObsoleteOrigin(const OriginProps& aOriginProps);
    1608             : 
    1609             :   nsresult
    1610             :   ProcessOriginDirectories();
    1611             : 
    1612             :   virtual nsresult
    1613             :   ProcessOriginDirectory(const OriginProps& aOriginProps) = 0;
    1614             : 
    1615             : private:
    1616             :   nsresult
    1617             :   RunOnMainThread();
    1618             : 
    1619             :   NS_IMETHOD
    1620             :   Run() override;
    1621             : };
    1622             : 
    1623           0 : struct StorageDirectoryHelper::OriginProps
    1624             : {
    1625             :   enum Type
    1626             :   {
    1627             :     eChrome,
    1628             :     eContent,
    1629             :     eObsolete
    1630             :   };
    1631             : 
    1632             :   nsCOMPtr<nsIFile> mDirectory;
    1633             :   nsString mLeafName;
    1634             :   nsCString mSpec;
    1635             :   OriginAttributes mAttrs;
    1636             :   int64_t mTimestamp;
    1637             :   nsCString mSuffix;
    1638             :   nsCString mGroup;
    1639             :   nsCString mOrigin;
    1640             : 
    1641             :   Type mType;
    1642             :   bool mNeedsRestore;
    1643             :   bool mNeedsRestore2;
    1644             :   bool mIgnore;
    1645             : 
    1646             : public:
    1647           0 :   explicit OriginProps()
    1648           0 :     : mTimestamp(0)
    1649             :     , mType(eContent)
    1650             :     , mNeedsRestore(false)
    1651             :     , mNeedsRestore2(false)
    1652           0 :     , mIgnore(false)
    1653           0 :   { }
    1654             : 
    1655             :   nsresult
    1656             :   Init(nsIFile* aDirectory);
    1657             : };
    1658             : 
    1659           0 : class MOZ_STACK_CLASS OriginParser final
    1660             : {
    1661             : public:
    1662             :   enum ResultType {
    1663             :     InvalidOrigin,
    1664             :     ObsoleteOrigin,
    1665             :     ValidOrigin
    1666             :   };
    1667             : 
    1668             : private:
    1669             :   static bool
    1670           0 :   IgnoreWhitespace(char16_t /* aChar */)
    1671             :   {
    1672           0 :     return false;
    1673             :   }
    1674             : 
    1675             :   typedef nsCCharSeparatedTokenizerTemplate<IgnoreWhitespace> Tokenizer;
    1676             : 
    1677             :   enum SchemeType {
    1678             :     eNone,
    1679             :     eFile,
    1680             :     eAbout
    1681             :   };
    1682             : 
    1683             :   enum State {
    1684             :     eExpectingAppIdOrScheme,
    1685             :     eExpectingInMozBrowser,
    1686             :     eExpectingScheme,
    1687             :     eExpectingEmptyToken1,
    1688             :     eExpectingEmptyToken2,
    1689             :     eExpectingEmptyToken3,
    1690             :     eExpectingHost,
    1691             :     eExpectingPort,
    1692             :     eExpectingEmptyTokenOrDriveLetterOrPathnameComponent,
    1693             :     eExpectingEmptyTokenOrPathnameComponent,
    1694             :     eComplete,
    1695             :     eHandledTrailingSeparator
    1696             :   };
    1697             : 
    1698             :   const nsCString mOrigin;
    1699             :   const OriginAttributes mOriginAttributes;
    1700             :   Tokenizer mTokenizer;
    1701             : 
    1702             :   uint32_t mAppId;
    1703             :   nsCString mScheme;
    1704             :   nsCString mHost;
    1705             :   Nullable<uint32_t> mPort;
    1706             :   nsTArray<nsCString> mPathnameComponents;
    1707             :   nsCString mHandledTokens;
    1708             : 
    1709             :   SchemeType mSchemeType;
    1710             :   State mState;
    1711             :   bool mInIsolatedMozBrowser;
    1712             :   bool mMaybeDriveLetter;
    1713             :   bool mError;
    1714             : 
    1715             : public:
    1716           0 :   OriginParser(const nsACString& aOrigin,
    1717             :                const OriginAttributes& aOriginAttributes)
    1718           0 :     : mOrigin(aOrigin)
    1719             :     , mOriginAttributes(aOriginAttributes)
    1720             :     , mTokenizer(aOrigin, '+')
    1721             :     , mAppId(kNoAppId)
    1722             :     , mPort()
    1723             :     , mSchemeType(eNone)
    1724             :     , mState(eExpectingAppIdOrScheme)
    1725             :     , mInIsolatedMozBrowser(false)
    1726             :     , mMaybeDriveLetter(false)
    1727           0 :     , mError(false)
    1728           0 :   { }
    1729             : 
    1730             :   static ResultType
    1731             :   ParseOrigin(const nsACString& aOrigin,
    1732             :               nsCString& aSpec,
    1733             :               OriginAttributes* aAttrs);
    1734             : 
    1735             :   ResultType
    1736             :   Parse(nsACString& aSpec, OriginAttributes* aAttrs);
    1737             : 
    1738             : private:
    1739             :   void
    1740             :   HandleScheme(const nsDependentCSubstring& aToken);
    1741             : 
    1742             :   void
    1743             :   HandlePathnameComponent(const nsDependentCSubstring& aToken);
    1744             : 
    1745             :   void
    1746             :   HandleToken(const nsDependentCSubstring& aToken);
    1747             : 
    1748             :   void
    1749             :   HandleTrailingSeparator();
    1750             : };
    1751             : 
    1752           0 : class CreateOrUpgradeDirectoryMetadataHelper final
    1753             :   : public StorageDirectoryHelper
    1754             : {
    1755             :   nsCOMPtr<nsIFile> mPermanentStorageDir;
    1756             : 
    1757             : public:
    1758           0 :   CreateOrUpgradeDirectoryMetadataHelper(nsIFile* aDirectory,
    1759             :                                          bool aPersistent)
    1760           0 :     : StorageDirectoryHelper(aDirectory, aPersistent)
    1761           0 :   { }
    1762             : 
    1763             :   nsresult
    1764             :   CreateOrUpgradeMetadataFiles();
    1765             : 
    1766             : private:
    1767             :   nsresult
    1768             :   MaybeUpgradeOriginDirectory(nsIFile* aDirectory);
    1769             : 
    1770             :   nsresult
    1771             :   ProcessOriginDirectory(const OriginProps& aOriginProps) override;
    1772             : };
    1773             : 
    1774           0 : class UpgradeStorageFrom0_0To1_0Helper final
    1775             :   : public StorageDirectoryHelper
    1776             : {
    1777             : public:
    1778           0 :   UpgradeStorageFrom0_0To1_0Helper(nsIFile* aDirectory,
    1779             :                                    bool aPersistent)
    1780           0 :     : StorageDirectoryHelper(aDirectory, aPersistent)
    1781           0 :   { }
    1782             : 
    1783             :   nsresult
    1784             :   DoUpgrade();
    1785             : 
    1786             : private:
    1787             :   nsresult
    1788             :   ProcessOriginDirectory(const OriginProps& aOriginProps) override;
    1789             : };
    1790             : 
    1791           0 : class UpgradeStorageFrom1_0To2_0Helper final
    1792             :   : public StorageDirectoryHelper
    1793             : {
    1794             : public:
    1795           0 :   UpgradeStorageFrom1_0To2_0Helper(nsIFile* aDirectory,
    1796             :                                    bool aPersistent)
    1797           0 :     : StorageDirectoryHelper(aDirectory, aPersistent)
    1798           0 :   { }
    1799             : 
    1800             :   nsresult
    1801             :   DoUpgrade();
    1802             : 
    1803             : private:
    1804             :   nsresult
    1805             :   MaybeUpgradeClients(const OriginProps& aOriginProps);
    1806             : 
    1807             :   nsresult
    1808             :   MaybeRemoveAppsData(const OriginProps& aOriginProps,
    1809             :                       bool* aRemoved);
    1810             : 
    1811             :   nsresult
    1812             :   MaybeStripObsoleteOriginAttributes(const OriginProps& aOriginProps,
    1813             :                                      bool* aStripped);
    1814             : 
    1815             :   nsresult
    1816             :   ProcessOriginDirectory(const OriginProps& aOriginProps) override;
    1817             : };
    1818             : 
    1819           0 : class RestoreDirectoryMetadata2Helper final
    1820             :   : public StorageDirectoryHelper
    1821             : {
    1822             : public:
    1823           0 :   RestoreDirectoryMetadata2Helper(nsIFile* aDirectory,
    1824             :                                   bool aPersistent)
    1825           0 :     : StorageDirectoryHelper(aDirectory, aPersistent)
    1826           0 :   { }
    1827             : 
    1828             :   nsresult
    1829             :   RestoreMetadata2File();
    1830             : 
    1831             : private:
    1832             :   nsresult
    1833             :   ProcessOriginDirectory(const OriginProps& aOriginProps) override;
    1834             : };
    1835             : 
    1836             : void
    1837           0 : SanitizeOriginString(nsCString& aOrigin)
    1838             : {
    1839             : 
    1840             : #ifdef XP_WIN
    1841             :   NS_ASSERTION(!strcmp(QuotaManager::kReplaceChars,
    1842             :                        FILE_ILLEGAL_CHARACTERS FILE_PATH_SEPARATOR),
    1843             :                "Illegal file characters have changed!");
    1844             : #endif
    1845             : 
    1846           0 :   aOrigin.ReplaceChar(QuotaManager::kReplaceChars, '+');
    1847           0 : }
    1848             : 
    1849             : nsresult
    1850           0 : CloneStoragePath(nsIFile* aBaseDir,
    1851             :                  const nsAString& aStorageName,
    1852             :                  nsAString& aStoragePath)
    1853             : {
    1854             :   nsresult rv;
    1855             : 
    1856           0 :   nsCOMPtr<nsIFile> storageDir;
    1857           0 :   rv = aBaseDir->Clone(getter_AddRefs(storageDir));
    1858           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1859           0 :     return rv;
    1860             :   }
    1861             : 
    1862           0 :   rv = storageDir->Append(aStorageName);
    1863           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1864           0 :     return rv;
    1865             :   }
    1866             : 
    1867           0 :   rv = storageDir->GetPath(aStoragePath);
    1868           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1869           0 :     return rv;
    1870             :   }
    1871             : 
    1872           0 :   return NS_OK;
    1873             : }
    1874             : 
    1875             : int64_t
    1876           0 : GetLastModifiedTime(nsIFile* aFile, bool aPersistent)
    1877             : {
    1878           0 :   AssertIsOnIOThread();
    1879           0 :   MOZ_ASSERT(aFile);
    1880             : 
    1881             :   class MOZ_STACK_CLASS Helper final
    1882             :   {
    1883             :   public:
    1884             :     static nsresult
    1885           0 :     GetLastModifiedTime(nsIFile* aFile, int64_t* aTimestamp)
    1886             :     {
    1887           0 :       AssertIsOnIOThread();
    1888           0 :       MOZ_ASSERT(aFile);
    1889           0 :       MOZ_ASSERT(aTimestamp);
    1890             : 
    1891             :       bool isDirectory;
    1892           0 :       nsresult rv = aFile->IsDirectory(&isDirectory);
    1893           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    1894           0 :         return rv;
    1895             :       }
    1896             : 
    1897           0 :       if (!isDirectory) {
    1898           0 :         nsString leafName;
    1899           0 :         rv = aFile->GetLeafName(leafName);
    1900           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    1901           0 :           return rv;
    1902             :         }
    1903             : 
    1904           0 :         if (IsOriginMetadata(leafName) ||
    1905           0 :             IsTempMetadata(leafName)) {
    1906           0 :           return NS_OK;
    1907             :         }
    1908             : 
    1909             :         int64_t timestamp;
    1910           0 :         rv = aFile->GetLastModifiedTime(&timestamp);
    1911           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    1912           0 :           return rv;
    1913             :         }
    1914             : 
    1915             :         // Need to convert from milliseconds to microseconds.
    1916           0 :         MOZ_ASSERT((INT64_MAX / PR_USEC_PER_MSEC) > timestamp);
    1917           0 :         timestamp *= int64_t(PR_USEC_PER_MSEC);
    1918             : 
    1919           0 :         if (timestamp > *aTimestamp) {
    1920           0 :           *aTimestamp = timestamp;
    1921             :         }
    1922           0 :         return NS_OK;
    1923             :       }
    1924             : 
    1925           0 :       nsCOMPtr<nsISimpleEnumerator> entries;
    1926           0 :       rv = aFile->GetDirectoryEntries(getter_AddRefs(entries));
    1927           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    1928           0 :         return rv;
    1929             :       }
    1930             : 
    1931             :       bool hasMore;
    1932           0 :       while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
    1933           0 :         nsCOMPtr<nsISupports> entry;
    1934           0 :         rv = entries->GetNext(getter_AddRefs(entry));
    1935           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    1936           0 :           return rv;
    1937             :         }
    1938             : 
    1939           0 :         nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
    1940           0 :         MOZ_ASSERT(file);
    1941             : 
    1942           0 :         rv = GetLastModifiedTime(file, aTimestamp);
    1943           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    1944           0 :           return rv;
    1945             :         }
    1946             :       }
    1947           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    1948           0 :         return rv;
    1949             :       }
    1950             : 
    1951           0 :       return NS_OK;
    1952             :     }
    1953             :   };
    1954             : 
    1955           0 :   if (aPersistent) {
    1956           0 :     return PR_Now();
    1957             :   }
    1958             : 
    1959           0 :   int64_t timestamp = INT64_MIN;
    1960           0 :   nsresult rv = Helper::GetLastModifiedTime(aFile, &timestamp);
    1961           0 :   if (NS_FAILED(rv)) {
    1962           0 :     timestamp = PR_Now();
    1963             :   }
    1964             : 
    1965           0 :   return timestamp;
    1966             : }
    1967             : 
    1968             : nsresult
    1969           0 : EnsureDirectory(nsIFile* aDirectory, bool* aCreated)
    1970             : {
    1971           0 :   AssertIsOnIOThread();
    1972             : 
    1973           0 :   nsresult rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
    1974           0 :   if (rv == NS_ERROR_FILE_ALREADY_EXISTS) {
    1975             :     bool isDirectory;
    1976           0 :     rv = aDirectory->IsDirectory(&isDirectory);
    1977           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1978           0 :     NS_ENSURE_TRUE(isDirectory, NS_ERROR_UNEXPECTED);
    1979             : 
    1980           0 :     *aCreated = false;
    1981             :   }
    1982             :   else {
    1983           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1984             : 
    1985           0 :     *aCreated = true;
    1986             :   }
    1987             : 
    1988           0 :   return NS_OK;
    1989             : }
    1990             : 
    1991             : nsresult
    1992           0 : EnsureOriginDirectory(nsIFile* aDirectory, bool* aCreated)
    1993             : {
    1994           0 :   AssertIsOnIOThread();
    1995             : 
    1996             :   nsresult rv;
    1997             : 
    1998             : #ifndef RELEASE_OR_BETA
    1999             :   bool exists;
    2000           0 :   rv = aDirectory->Exists(&exists);
    2001           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2002           0 :     return rv;
    2003             :   }
    2004             : 
    2005           0 :   if (!exists) {
    2006           0 :     nsString leafName;
    2007           0 :     nsresult rv = aDirectory->GetLeafName(leafName);
    2008           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    2009           0 :       return rv;
    2010             :     }
    2011             : 
    2012           0 :     if (!leafName.EqualsLiteral(kChromeOrigin)) {
    2013           0 :       nsCString spec;
    2014           0 :       OriginAttributes attrs;
    2015             :       OriginParser::ResultType result =
    2016           0 :         OriginParser::ParseOrigin(NS_ConvertUTF16toUTF8(leafName),
    2017             :                                   spec,
    2018           0 :                                   &attrs);
    2019           0 :       if (NS_WARN_IF(result != OriginParser::ValidOrigin)) {
    2020           0 :         QM_WARNING("Preventing creation of a new origin directory which is not "
    2021             :                    "supported by our origin parser or is obsolete!");
    2022             : 
    2023           0 :         return NS_ERROR_FAILURE;
    2024             :       }
    2025             :     }
    2026             :   }
    2027             : #endif
    2028             : 
    2029           0 :   rv = EnsureDirectory(aDirectory, aCreated);
    2030           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2031           0 :     return rv;
    2032             :   }
    2033             : 
    2034           0 :   return NS_OK;
    2035             : }
    2036             : 
    2037             : enum FileFlag {
    2038             :   kTruncateFileFlag,
    2039             :   kUpdateFileFlag,
    2040             :   kAppendFileFlag
    2041             : };
    2042             : 
    2043             : nsresult
    2044           0 : GetOutputStream(nsIFile* aFile,
    2045             :                 FileFlag aFileFlag,
    2046             :                 nsIOutputStream** aStream)
    2047             : {
    2048           0 :   AssertIsOnIOThread();
    2049             : 
    2050             :   nsresult rv;
    2051             : 
    2052           0 :   nsCOMPtr<nsIOutputStream> outputStream;
    2053           0 :   switch (aFileFlag) {
    2054             :     case kTruncateFileFlag: {
    2055           0 :       rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream),
    2056           0 :                                        aFile);
    2057           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    2058           0 :         return rv;
    2059             :       }
    2060             : 
    2061           0 :       break;
    2062             :     }
    2063             : 
    2064             :     case kUpdateFileFlag: {
    2065             :       bool exists;
    2066           0 :       rv = aFile->Exists(&exists);
    2067           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    2068           0 :         return rv;
    2069             :       }
    2070             : 
    2071           0 :       if (!exists) {
    2072           0 :         *aStream = nullptr;
    2073           0 :         return NS_OK;
    2074             :       }
    2075             : 
    2076           0 :       nsCOMPtr<nsIFileStream> stream;
    2077           0 :       rv = NS_NewLocalFileStream(getter_AddRefs(stream), aFile);
    2078           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    2079           0 :         return rv;
    2080             :       }
    2081             : 
    2082           0 :       outputStream = do_QueryInterface(stream);
    2083           0 :       if (NS_WARN_IF(!outputStream)) {
    2084           0 :         return NS_ERROR_FAILURE;
    2085             :       }
    2086             : 
    2087           0 :       break;
    2088             :     }
    2089             : 
    2090             :     case kAppendFileFlag: {
    2091           0 :       rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream),
    2092             :                                        aFile,
    2093           0 :                                        PR_WRONLY | PR_CREATE_FILE | PR_APPEND);
    2094           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    2095           0 :         return rv;
    2096             :       }
    2097             : 
    2098           0 :       break;
    2099             :     }
    2100             : 
    2101             :     default:
    2102           0 :       MOZ_CRASH("Should never get here!");
    2103             :   }
    2104             : 
    2105           0 :   outputStream.forget(aStream);
    2106           0 :   return NS_OK;
    2107             : }
    2108             : 
    2109             : nsresult
    2110           0 : GetBinaryOutputStream(nsIFile* aFile,
    2111             :                       FileFlag aFileFlag,
    2112             :                       nsIBinaryOutputStream** aStream)
    2113             : {
    2114           0 :   nsCOMPtr<nsIOutputStream> outputStream;
    2115           0 :   nsresult rv = GetOutputStream(aFile,
    2116             :                                 aFileFlag,
    2117           0 :                                 getter_AddRefs(outputStream));
    2118           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2119           0 :     return rv;
    2120             :   }
    2121             : 
    2122             :   nsCOMPtr<nsIBinaryOutputStream> binaryStream =
    2123           0 :     do_CreateInstance("@mozilla.org/binaryoutputstream;1");
    2124           0 :   if (NS_WARN_IF(!binaryStream)) {
    2125           0 :     return NS_ERROR_FAILURE;
    2126             :   }
    2127             : 
    2128           0 :   rv = binaryStream->SetOutputStream(outputStream);
    2129           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2130           0 :     return rv;
    2131             :   }
    2132             : 
    2133           0 :   binaryStream.forget(aStream);
    2134           0 :   return NS_OK;
    2135             : }
    2136             : 
    2137             : void
    2138           0 : GetJarPrefix(uint32_t aAppId,
    2139             :              bool aInIsolatedMozBrowser,
    2140             :              nsACString& aJarPrefix)
    2141             : {
    2142           0 :   MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
    2143             : 
    2144           0 :   if (aAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
    2145           0 :     aAppId = nsIScriptSecurityManager::NO_APP_ID;
    2146             :   }
    2147             : 
    2148           0 :   aJarPrefix.Truncate();
    2149             : 
    2150             :   // Fallback.
    2151           0 :   if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInIsolatedMozBrowser) {
    2152           0 :     return;
    2153             :   }
    2154             : 
    2155             :   // aJarPrefix = appId + "+" + { 't', 'f' } + "+";
    2156           0 :   aJarPrefix.AppendInt(aAppId);
    2157           0 :   aJarPrefix.Append('+');
    2158           0 :   aJarPrefix.Append(aInIsolatedMozBrowser ? 't' : 'f');
    2159           0 :   aJarPrefix.Append('+');
    2160             : }
    2161             : 
    2162             : nsresult
    2163           0 : CreateDirectoryMetadata(nsIFile* aDirectory, int64_t aTimestamp,
    2164             :                         const nsACString& aSuffix, const nsACString& aGroup,
    2165             :                         const nsACString& aOrigin)
    2166             : {
    2167           0 :   AssertIsOnIOThread();
    2168             : 
    2169           0 :   OriginAttributes groupAttributes;
    2170             : 
    2171           0 :   nsCString groupNoSuffix;
    2172           0 :   bool ok = groupAttributes.PopulateFromOrigin(aGroup, groupNoSuffix);
    2173           0 :   if (!ok) {
    2174           0 :     return NS_ERROR_FAILURE;
    2175             :   }
    2176             : 
    2177           0 :   nsCString groupPrefix;
    2178           0 :   GetJarPrefix(groupAttributes.mAppId,
    2179           0 :                groupAttributes.mInIsolatedMozBrowser,
    2180           0 :                groupPrefix);
    2181             : 
    2182           0 :   nsCString group = groupPrefix + groupNoSuffix;
    2183             : 
    2184           0 :   OriginAttributes originAttributes;
    2185             : 
    2186           0 :   nsCString originNoSuffix;
    2187           0 :   ok = originAttributes.PopulateFromOrigin(aOrigin, originNoSuffix);
    2188           0 :   if (!ok) {
    2189           0 :     return NS_ERROR_FAILURE;
    2190             :   }
    2191             : 
    2192           0 :   nsCString originPrefix;
    2193           0 :   GetJarPrefix(originAttributes.mAppId,
    2194           0 :                originAttributes.mInIsolatedMozBrowser,
    2195           0 :                originPrefix);
    2196             : 
    2197           0 :   nsCString origin = originPrefix + originNoSuffix;
    2198             : 
    2199           0 :   MOZ_ASSERT(groupPrefix == originPrefix);
    2200             : 
    2201           0 :   nsCOMPtr<nsIFile> file;
    2202           0 :   nsresult rv = aDirectory->Clone(getter_AddRefs(file));
    2203           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2204           0 :     return rv;
    2205             :   }
    2206             : 
    2207           0 :   rv = file->Append(NS_LITERAL_STRING(METADATA_TMP_FILE_NAME));
    2208           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2209           0 :     return rv;
    2210             :   }
    2211             : 
    2212           0 :   nsCOMPtr<nsIBinaryOutputStream> stream;
    2213           0 :   rv = GetBinaryOutputStream(file, kTruncateFileFlag, getter_AddRefs(stream));
    2214           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2215           0 :     return rv;
    2216             :   }
    2217             : 
    2218           0 :   MOZ_ASSERT(stream);
    2219             : 
    2220           0 :   rv = stream->Write64(aTimestamp);
    2221           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2222           0 :     return rv;
    2223             :   }
    2224             : 
    2225           0 :   rv = stream->WriteStringZ(group.get());
    2226           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2227           0 :     return rv;
    2228             :   }
    2229             : 
    2230           0 :   rv = stream->WriteStringZ(origin.get());
    2231           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2232           0 :     return rv;
    2233             :   }
    2234             : 
    2235             :   // Currently unused (used to be isApp).
    2236           0 :   rv = stream->WriteBoolean(false);
    2237           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2238           0 :     return rv;
    2239             :   }
    2240             : 
    2241           0 :   rv = stream->Flush();
    2242           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2243           0 :     return rv;
    2244             :   }
    2245             : 
    2246           0 :   rv = stream->Close();
    2247           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2248           0 :     return rv;
    2249             :   }
    2250             : 
    2251           0 :   rv = file->RenameTo(nullptr, NS_LITERAL_STRING(METADATA_FILE_NAME));
    2252           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2253           0 :     return rv;
    2254             :   }
    2255             : 
    2256           0 :   return NS_OK;
    2257             : }
    2258             : 
    2259             : nsresult
    2260           0 : CreateDirectoryMetadata2(nsIFile* aDirectory,
    2261             :                          int64_t aTimestamp,
    2262             :                          bool aPersisted,
    2263             :                          const nsACString& aSuffix,
    2264             :                          const nsACString& aGroup,
    2265             :                          const nsACString& aOrigin)
    2266             : {
    2267           0 :   AssertIsOnIOThread();
    2268           0 :   MOZ_ASSERT(aDirectory);
    2269             : 
    2270           0 :   nsCOMPtr<nsIFile> file;
    2271           0 :   nsresult rv = aDirectory->Clone(getter_AddRefs(file));
    2272           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2273           0 :     return rv;
    2274             :   }
    2275             : 
    2276           0 :   rv = file->Append(NS_LITERAL_STRING(METADATA_V2_TMP_FILE_NAME));
    2277           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2278           0 :     return rv;
    2279             :   }
    2280             : 
    2281           0 :   nsCOMPtr<nsIBinaryOutputStream> stream;
    2282           0 :   rv = GetBinaryOutputStream(file, kTruncateFileFlag, getter_AddRefs(stream));
    2283           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2284           0 :     return rv;
    2285             :   }
    2286             : 
    2287           0 :   MOZ_ASSERT(stream);
    2288             : 
    2289           0 :   rv = stream->Write64(aTimestamp);
    2290           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2291           0 :     return rv;
    2292             :   }
    2293             : 
    2294           0 :   rv = stream->WriteBoolean(aPersisted);
    2295           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2296           0 :     return rv;
    2297             :   }
    2298             : 
    2299             :   // Reserved data 1
    2300           0 :   rv = stream->Write32(0);
    2301           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2302           0 :     return rv;
    2303             :   }
    2304             : 
    2305             :   // Reserved data 2
    2306           0 :   rv = stream->Write32(0);
    2307           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2308           0 :     return rv;
    2309             :   }
    2310             : 
    2311             :   // The suffix isn't used right now, but we might need it in future. It's
    2312             :   // a bit of redundancy we can live with given how painful is to upgrade
    2313             :   // metadata files.
    2314           0 :   rv = stream->WriteStringZ(PromiseFlatCString(aSuffix).get());
    2315           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2316           0 :     return rv;
    2317             :   }
    2318             : 
    2319           0 :   rv = stream->WriteStringZ(PromiseFlatCString(aGroup).get());
    2320           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2321           0 :     return rv;
    2322             :   }
    2323             : 
    2324           0 :   rv = stream->WriteStringZ(PromiseFlatCString(aOrigin).get());
    2325           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2326           0 :     return rv;
    2327             :   }
    2328             : 
    2329             :   // Currently unused (used to be isApp).
    2330           0 :   rv = stream->WriteBoolean(false);
    2331           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2332           0 :     return rv;
    2333             :   }
    2334             : 
    2335           0 :   rv = stream->Flush();
    2336           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2337           0 :     return rv;
    2338             :   }
    2339             : 
    2340           0 :   rv = stream->Close();
    2341           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2342           0 :     return rv;
    2343             :   }
    2344             : 
    2345           0 :   rv = file->RenameTo(nullptr, NS_LITERAL_STRING(METADATA_V2_FILE_NAME));
    2346           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2347           0 :     return rv;
    2348             :   }
    2349             : 
    2350           0 :   return NS_OK;
    2351             : }
    2352             : 
    2353             : nsresult
    2354           0 : CreateDirectoryMetadataFiles(nsIFile* aDirectory,
    2355             :                              bool aPersisted,
    2356             :                              const nsACString& aSuffix,
    2357             :                              const nsACString& aGroup,
    2358             :                              const nsACString& aOrigin,
    2359             :                              int64_t* aTimestamp)
    2360             : {
    2361           0 :   AssertIsOnIOThread();
    2362             : 
    2363           0 :   int64_t timestamp = PR_Now();
    2364             : 
    2365             :   nsresult rv = CreateDirectoryMetadata(aDirectory,
    2366             :                                         timestamp,
    2367             :                                         aSuffix,
    2368             :                                         aGroup,
    2369           0 :                                         aOrigin);
    2370           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2371           0 :     return rv;
    2372             :   }
    2373             : 
    2374           0 :   rv = CreateDirectoryMetadata2(aDirectory,
    2375             :                                 timestamp,
    2376             :                                 aPersisted,
    2377             :                                 aSuffix,
    2378             :                                 aGroup,
    2379           0 :                                 aOrigin);
    2380           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2381           0 :     return rv;
    2382             :   }
    2383             : 
    2384           0 :   if (aTimestamp) {
    2385           0 :     *aTimestamp = timestamp;
    2386             :   }
    2387           0 :   return NS_OK;
    2388             : }
    2389             : 
    2390             : nsresult
    2391           0 : GetBinaryInputStream(nsIFile* aDirectory,
    2392             :                      const nsAString& aFilename,
    2393             :                      nsIBinaryInputStream** aStream)
    2394             : {
    2395           0 :   MOZ_ASSERT(!NS_IsMainThread());
    2396           0 :   MOZ_ASSERT(aDirectory);
    2397           0 :   MOZ_ASSERT(aStream);
    2398             : 
    2399           0 :   nsCOMPtr<nsIFile> file;
    2400           0 :   nsresult rv = aDirectory->Clone(getter_AddRefs(file));
    2401           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2402           0 :     return rv;
    2403             :   }
    2404             : 
    2405           0 :   rv = file->Append(aFilename);
    2406           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2407           0 :     return rv;
    2408             :   }
    2409             : 
    2410           0 :   nsCOMPtr<nsIInputStream> stream;
    2411           0 :   rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file);
    2412           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2413           0 :     return rv;
    2414             :   }
    2415             : 
    2416           0 :   nsCOMPtr<nsIInputStream> bufferedStream;
    2417           0 :   rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream), stream, 512);
    2418           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2419           0 :     return rv;
    2420             :   }
    2421             : 
    2422             :   nsCOMPtr<nsIBinaryInputStream> binaryStream =
    2423           0 :     do_CreateInstance("@mozilla.org/binaryinputstream;1");
    2424           0 :   if (NS_WARN_IF(!binaryStream)) {
    2425           0 :     return NS_ERROR_FAILURE;
    2426             :   }
    2427             : 
    2428           0 :   rv = binaryStream->SetInputStream(bufferedStream);
    2429           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2430           0 :     return rv;
    2431             :   }
    2432             : 
    2433           0 :   binaryStream.forget(aStream);
    2434           0 :   return NS_OK;
    2435             : }
    2436             : 
    2437             : // This method computes and returns our best guess for the temporary storage
    2438             : // limit (in bytes), based on the amount of space users have free on their hard
    2439             : // drive and on given temporary storage usage (also in bytes).
    2440             : nsresult
    2441           0 : GetTemporaryStorageLimit(nsIFile* aDirectory, uint64_t aCurrentUsage,
    2442             :                          uint64_t* aLimit)
    2443             : {
    2444             :   // Check for free space on device where temporary storage directory lives.
    2445             :   int64_t bytesAvailable;
    2446           0 :   nsresult rv = aDirectory->GetDiskSpaceAvailable(&bytesAvailable);
    2447           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2448             : 
    2449           0 :   NS_ASSERTION(bytesAvailable >= 0, "Negative bytes available?!");
    2450             : 
    2451             :   uint64_t availableKB =
    2452           0 :     static_cast<uint64_t>((bytesAvailable + aCurrentUsage) / 1024);
    2453             : 
    2454             :   // Grow/shrink in gChunkSizeKB units, deliberately, so that in the common case
    2455             :   // we don't shrink temporary storage and evict origin data every time we
    2456             :   // initialize.
    2457           0 :   availableKB = (availableKB / gChunkSizeKB) * gChunkSizeKB;
    2458             : 
    2459             :   // Allow temporary storage to consume up to half the available space.
    2460           0 :   uint64_t resultKB = availableKB * .50;
    2461             : 
    2462           0 :   *aLimit = resultKB * 1024;
    2463           0 :   return NS_OK;
    2464             : }
    2465             : 
    2466             : } // namespace
    2467             : 
    2468             : /*******************************************************************************
    2469             :  * Exported functions
    2470             :  ******************************************************************************/
    2471             : 
    2472             : PQuotaParent*
    2473           0 : AllocPQuotaParent()
    2474             : {
    2475           0 :   AssertIsOnBackgroundThread();
    2476             : 
    2477           0 :   if (NS_WARN_IF(QuotaManager::IsShuttingDown())) {
    2478           0 :     return nullptr;
    2479             :   }
    2480             : 
    2481           0 :   RefPtr<Quota> actor = new Quota();
    2482             : 
    2483           0 :   return actor.forget().take();
    2484             : }
    2485             : 
    2486             : bool
    2487           0 : DeallocPQuotaParent(PQuotaParent* aActor)
    2488             : {
    2489           0 :   AssertIsOnBackgroundThread();
    2490           0 :   MOZ_ASSERT(aActor);
    2491             : 
    2492           0 :   RefPtr<Quota> actor = dont_AddRef(static_cast<Quota*>(aActor));
    2493           0 :   return true;
    2494             : }
    2495             : 
    2496             : /*******************************************************************************
    2497             :  * Directory lock
    2498             :  ******************************************************************************/
    2499             : 
    2500           0 : DirectoryLockImpl::DirectoryLockImpl(QuotaManager* aQuotaManager,
    2501             :                                      const Nullable<PersistenceType>& aPersistenceType,
    2502             :                                      const nsACString& aGroup,
    2503             :                                      const OriginScope& aOriginScope,
    2504             :                                      const Nullable<Client::Type>& aClientType,
    2505             :                                      bool aExclusive,
    2506             :                                      bool aInternal,
    2507           0 :                                      OpenDirectoryListener* aOpenListener)
    2508             :   : mQuotaManager(aQuotaManager)
    2509             :   , mPersistenceType(aPersistenceType)
    2510             :   , mGroup(aGroup)
    2511             :   , mOriginScope(aOriginScope)
    2512             :   , mClientType(aClientType)
    2513             :   , mOpenListener(aOpenListener)
    2514             :   , mExclusive(aExclusive)
    2515             :   , mInternal(aInternal)
    2516           0 :   , mInvalidated(false)
    2517             : {
    2518           0 :   AssertIsOnOwningThread();
    2519           0 :   MOZ_ASSERT(aQuotaManager);
    2520           0 :   MOZ_ASSERT_IF(aOriginScope.IsOrigin(), !aOriginScope.GetOrigin().IsEmpty());
    2521           0 :   MOZ_ASSERT_IF(!aInternal, !aPersistenceType.IsNull());
    2522           0 :   MOZ_ASSERT_IF(!aInternal,
    2523             :                 aPersistenceType.Value() != PERSISTENCE_TYPE_INVALID);
    2524           0 :   MOZ_ASSERT_IF(!aInternal, !aGroup.IsEmpty());
    2525           0 :   MOZ_ASSERT_IF(!aInternal, aOriginScope.IsOrigin());
    2526           0 :   MOZ_ASSERT_IF(!aInternal, !aClientType.IsNull());
    2527           0 :   MOZ_ASSERT_IF(!aInternal, aClientType.Value() != Client::TYPE_MAX);
    2528           0 :   MOZ_ASSERT_IF(!aInternal, aOpenListener);
    2529           0 : }
    2530             : 
    2531           0 : DirectoryLockImpl::~DirectoryLockImpl()
    2532             : {
    2533           0 :   AssertIsOnOwningThread();
    2534           0 :   MOZ_ASSERT(mQuotaManager);
    2535             : 
    2536           0 :   for (DirectoryLockImpl* blockingLock : mBlocking) {
    2537           0 :     blockingLock->MaybeUnblock(this);
    2538             :   }
    2539             : 
    2540           0 :   mBlocking.Clear();
    2541             : 
    2542           0 :   mQuotaManager->UnregisterDirectoryLock(this);
    2543           0 : }
    2544             : 
    2545             : #ifdef DEBUG
    2546             : 
    2547             : void
    2548           0 : DirectoryLockImpl::AssertIsOnOwningThread() const
    2549             : {
    2550           0 :   MOZ_ASSERT(mQuotaManager);
    2551           0 :   mQuotaManager->AssertIsOnOwningThread();
    2552           0 : }
    2553             : 
    2554             : #endif // DEBUG
    2555             : 
    2556             : bool
    2557           0 : DirectoryLockImpl::MustWaitFor(const DirectoryLockImpl& aExistingLock)
    2558             : {
    2559           0 :   AssertIsOnOwningThread();
    2560             : 
    2561             :   // Waiting is never required if the ops in comparison represent shared locks.
    2562           0 :   if (!aExistingLock.mExclusive && !mExclusive) {
    2563           0 :     return false;
    2564             :   }
    2565             : 
    2566             :   // If the persistence types don't overlap, the op can proceed.
    2567           0 :   if (!aExistingLock.mPersistenceType.IsNull() && !mPersistenceType.IsNull() &&
    2568           0 :       aExistingLock.mPersistenceType.Value() != mPersistenceType.Value()) {
    2569           0 :     return false;
    2570             :   }
    2571             : 
    2572             :   // If the origin scopes don't overlap, the op can proceed.
    2573           0 :   bool match = aExistingLock.mOriginScope.Matches(mOriginScope);
    2574           0 :   if (!match) {
    2575           0 :     return false;
    2576             :   }
    2577             : 
    2578             :   // If the client types don't overlap, the op can proceed.
    2579           0 :   if (!aExistingLock.mClientType.IsNull() && !mClientType.IsNull() &&
    2580           0 :       aExistingLock.mClientType.Value() != mClientType.Value()) {
    2581           0 :     return false;
    2582             :   }
    2583             : 
    2584             :   // Otherwise, when all attributes overlap (persistence type, origin scope and
    2585             :   // client type) the op must wait.
    2586           0 :   return true;
    2587             : }
    2588             : 
    2589             : void
    2590           0 : DirectoryLockImpl::NotifyOpenListener()
    2591             : {
    2592           0 :   AssertIsOnOwningThread();
    2593           0 :   MOZ_ASSERT(mQuotaManager);
    2594           0 :   MOZ_ASSERT(mOpenListener);
    2595             : 
    2596           0 :   if (mInvalidated) {
    2597           0 :     mOpenListener->DirectoryLockFailed();
    2598             :   } else {
    2599           0 :     mOpenListener->DirectoryLockAcquired(this);
    2600             :   }
    2601             : 
    2602           0 :   mOpenListener = nullptr;
    2603             : 
    2604           0 :   mQuotaManager->RemovePendingDirectoryLock(this);
    2605           0 : }
    2606             : 
    2607             : nsresult
    2608           0 : QuotaManager::
    2609             : CreateRunnable::Init()
    2610             : {
    2611           0 :   MOZ_ASSERT(NS_IsMainThread());
    2612           0 :   MOZ_ASSERT(mState == State::Initial);
    2613             : 
    2614             :   nsresult rv;
    2615             : 
    2616           0 :   nsCOMPtr<nsIFile> baseDir;
    2617           0 :   rv = NS_GetSpecialDirectory(NS_APP_INDEXEDDB_PARENT_DIR,
    2618           0 :                               getter_AddRefs(baseDir));
    2619           0 :   if (NS_FAILED(rv)) {
    2620           0 :     rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
    2621           0 :                                 getter_AddRefs(baseDir));
    2622             :   }
    2623           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2624           0 :     return rv;
    2625             :   }
    2626             : 
    2627           0 :   rv = baseDir->GetPath(mBaseDirPath);
    2628           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2629           0 :     return rv;
    2630             :   }
    2631             : 
    2632           0 :   return NS_OK;
    2633             : }
    2634             : 
    2635             : nsresult
    2636           0 : QuotaManager::
    2637             : CreateRunnable::CreateManager()
    2638             : {
    2639           0 :   AssertIsOnOwningThread();
    2640           0 :   MOZ_ASSERT(mState == State::CreatingManager);
    2641             : 
    2642           0 :   mManager = new QuotaManager();
    2643             : 
    2644           0 :   nsresult rv = mManager->Init(mBaseDirPath);
    2645           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2646           0 :     return rv;
    2647             :   }
    2648             : 
    2649           0 :   return NS_OK;
    2650             : }
    2651             : 
    2652             : nsresult
    2653           0 : QuotaManager::
    2654             : CreateRunnable::RegisterObserver()
    2655             : {
    2656           0 :   MOZ_ASSERT(NS_IsMainThread());
    2657           0 :   MOZ_ASSERT(mState == State::RegisteringObserver);
    2658             : 
    2659           0 :   if (NS_FAILED(Preferences::AddIntVarCache(&gFixedLimitKB, PREF_FIXED_LIMIT,
    2660           0 :                                             kDefaultFixedLimitKB)) ||
    2661           0 :       NS_FAILED(Preferences::AddUintVarCache(&gChunkSizeKB,
    2662             :                                              PREF_CHUNK_SIZE,
    2663             :                                              kDefaultChunkSizeKB))) {
    2664           0 :     NS_WARNING("Unable to respond to temp storage pref changes!");
    2665             :   }
    2666             : 
    2667           0 :   if (NS_FAILED(Preferences::AddBoolVarCache(&gTestingEnabled,
    2668             :                                              PREF_TESTING_FEATURES, false))) {
    2669           0 :     NS_WARNING("Unable to respond to testing pref changes!");
    2670             :   }
    2671             : 
    2672             :   nsCOMPtr<nsIObserverService> observerService =
    2673           0 :     mozilla::services::GetObserverService();
    2674           0 :   if (NS_WARN_IF(!observerService)) {
    2675           0 :     return NS_ERROR_FAILURE;
    2676             :   }
    2677             : 
    2678           0 :   nsCOMPtr<nsIObserver> observer = new ShutdownObserver(mOwningThread);
    2679             : 
    2680             :   nsresult rv =
    2681           0 :     observerService->AddObserver(observer,
    2682             :                                  PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID,
    2683           0 :                                  false);
    2684           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2685           0 :     return rv;
    2686             :   }
    2687             : 
    2688             :   // This service has to be started on the main thread currently.
    2689             :   nsCOMPtr<mozIStorageService> ss =
    2690           0 :     do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
    2691           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2692           0 :     return rv;
    2693             :   }
    2694             : 
    2695           0 :   QuotaManagerService* qms = QuotaManagerService::GetOrCreate();
    2696           0 :   if (NS_WARN_IF(!qms)) {
    2697           0 :     return rv;
    2698             :   }
    2699             : 
    2700           0 :   qms->NoteLiveManager(mManager);
    2701             : 
    2702           0 :   for (RefPtr<Client>& client : mManager->mClients) {
    2703           0 :     client->DidInitialize(mManager);
    2704             :   }
    2705             : 
    2706           0 :   return NS_OK;
    2707             : }
    2708             : 
    2709             : void
    2710           0 : QuotaManager::
    2711             : CreateRunnable::CallCallbacks()
    2712             : {
    2713           0 :   AssertIsOnOwningThread();
    2714           0 :   MOZ_ASSERT(mState == State::CallingCallbacks);
    2715             : 
    2716           0 :   gCreateRunnable = nullptr;
    2717             : 
    2718           0 :   if (NS_FAILED(mResultCode)) {
    2719           0 :     gCreateFailed = true;
    2720             :   } else {
    2721           0 :     gInstance = mManager;
    2722             :   }
    2723             : 
    2724           0 :   mManager = nullptr;
    2725             : 
    2726           0 :   nsTArray<nsCOMPtr<nsIRunnable>> callbacks;
    2727           0 :   mCallbacks.SwapElements(callbacks);
    2728             : 
    2729           0 :   for (nsCOMPtr<nsIRunnable>& callback : callbacks) {
    2730           0 :     Unused << callback->Run();
    2731             :   }
    2732           0 : }
    2733             : 
    2734             : auto
    2735           0 : QuotaManager::
    2736             : CreateRunnable::GetNextState(nsCOMPtr<nsIEventTarget>& aThread) -> State
    2737             : {
    2738           0 :   switch (mState) {
    2739             :     case State::Initial:
    2740           0 :       aThread = mOwningThread;
    2741           0 :       return State::CreatingManager;
    2742             :     case State::CreatingManager:
    2743           0 :       aThread = GetMainThreadEventTarget();
    2744           0 :       return State::RegisteringObserver;
    2745             :     case State::RegisteringObserver:
    2746           0 :       aThread = mOwningThread;
    2747           0 :       return State::CallingCallbacks;
    2748             :     case State::CallingCallbacks:
    2749           0 :       aThread = nullptr;
    2750           0 :       return State::Completed;
    2751             :     default:
    2752           0 :       MOZ_CRASH("Bad state!");
    2753             :   }
    2754             : }
    2755             : 
    2756             : NS_IMETHODIMP
    2757           0 : QuotaManager::
    2758             : CreateRunnable::Run()
    2759             : {
    2760             :   nsresult rv;
    2761             : 
    2762           0 :   switch (mState) {
    2763             :     case State::Initial:
    2764           0 :       rv = Init();
    2765           0 :       break;
    2766             : 
    2767             :     case State::CreatingManager:
    2768           0 :       rv = CreateManager();
    2769           0 :       break;
    2770             : 
    2771             :     case State::RegisteringObserver:
    2772           0 :       rv = RegisterObserver();
    2773           0 :       break;
    2774             : 
    2775             :     case State::CallingCallbacks:
    2776           0 :       CallCallbacks();
    2777           0 :       rv = NS_OK;
    2778           0 :       break;
    2779             : 
    2780             :     case State::Completed:
    2781             :     default:
    2782           0 :       MOZ_CRASH("Bad state!");
    2783             :   }
    2784             : 
    2785           0 :   nsCOMPtr<nsIEventTarget> thread;
    2786           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2787           0 :     if (NS_SUCCEEDED(mResultCode)) {
    2788           0 :       mResultCode = rv;
    2789             :     }
    2790             : 
    2791           0 :     mState = State::CallingCallbacks;
    2792           0 :     thread = mOwningThread;
    2793             :   } else {
    2794           0 :     mState = GetNextState(thread);
    2795             :   }
    2796             : 
    2797           0 :   if (thread) {
    2798           0 :     MOZ_ALWAYS_SUCCEEDS(thread->Dispatch(this, NS_DISPATCH_NORMAL));
    2799             :   }
    2800             : 
    2801           0 :   return NS_OK;
    2802             : }
    2803             : 
    2804             : NS_IMETHODIMP
    2805           0 : QuotaManager::
    2806             : ShutdownRunnable::Run()
    2807             : {
    2808           0 :   if (NS_IsMainThread()) {
    2809           0 :     mDone = true;
    2810             : 
    2811           0 :     return NS_OK;
    2812             :   }
    2813             : 
    2814           0 :   AssertIsOnBackgroundThread();
    2815             : 
    2816           0 :   RefPtr<QuotaManager> quotaManager = gInstance.get();
    2817           0 :   if (quotaManager) {
    2818           0 :     quotaManager->Shutdown();
    2819             : 
    2820           0 :     gInstance = nullptr;
    2821             :   }
    2822             : 
    2823           0 :   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
    2824             : 
    2825           0 :   return NS_OK;
    2826             : }
    2827             : 
    2828           0 : NS_IMPL_ISUPPORTS(QuotaManager::ShutdownObserver, nsIObserver)
    2829             : 
    2830             : NS_IMETHODIMP
    2831           0 : QuotaManager::
    2832             : ShutdownObserver::Observe(nsISupports* aSubject,
    2833             :                           const char* aTopic,
    2834             :                           const char16_t* aData)
    2835             : {
    2836           0 :   MOZ_ASSERT(NS_IsMainThread());
    2837           0 :   MOZ_ASSERT(!strcmp(aTopic, PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID));
    2838           0 :   MOZ_ASSERT(gInstance);
    2839             : 
    2840             :   nsCOMPtr<nsIObserverService> observerService =
    2841           0 :     mozilla::services::GetObserverService();
    2842           0 :   if (NS_WARN_IF(!observerService)) {
    2843           0 :     return NS_ERROR_FAILURE;
    2844             :   }
    2845             : 
    2846             :   // Unregister ourselves from the observer service first to make sure the
    2847             :   // nested event loop below will not cause re-entrancy issues.
    2848             :   Unused <<
    2849           0 :     observerService->RemoveObserver(this,
    2850           0 :                                     PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID);
    2851             : 
    2852           0 :   QuotaManagerService* qms = QuotaManagerService::Get();
    2853           0 :   MOZ_ASSERT(qms);
    2854             : 
    2855           0 :   qms->NoteShuttingDownManager();
    2856             : 
    2857           0 :   for (RefPtr<Client>& client : gInstance->mClients) {
    2858           0 :     client->WillShutdown();
    2859             :   }
    2860             : 
    2861           0 :   bool done = false;
    2862             : 
    2863           0 :   RefPtr<ShutdownRunnable> shutdownRunnable = new ShutdownRunnable(done);
    2864           0 :   MOZ_ALWAYS_SUCCEEDS(
    2865             :     mBackgroundThread->Dispatch(shutdownRunnable, NS_DISPATCH_NORMAL));
    2866             : 
    2867           0 :   MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return done; }));
    2868             : 
    2869           0 :   return NS_OK;
    2870             : }
    2871             : 
    2872             : /*******************************************************************************
    2873             :  * Quota object
    2874             :  ******************************************************************************/
    2875             : 
    2876             : NS_IMETHODIMP
    2877           0 : QuotaObject::
    2878             : StoragePressureRunnable::Run()
    2879             : {
    2880           0 :   MOZ_ASSERT(NS_IsMainThread());
    2881             : 
    2882           0 :   nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
    2883           0 :   if (NS_WARN_IF(!obsSvc)) {
    2884           0 :     return NS_ERROR_FAILURE;
    2885             :   }
    2886             : 
    2887             :   nsCOMPtr<nsISupportsPRUint64> wrapper =
    2888           0 :     do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);
    2889           0 :   if (NS_WARN_IF(!wrapper)) {
    2890           0 :     return NS_ERROR_FAILURE;
    2891             :   }
    2892             : 
    2893           0 :   wrapper->SetData(mUsage);
    2894             : 
    2895           0 :   obsSvc->NotifyObservers(wrapper, "QuotaManager::StoragePressure", u"");
    2896             : 
    2897           0 :   return NS_OK;
    2898             : }
    2899             : 
    2900             : void
    2901           0 : QuotaObject::AddRef()
    2902             : {
    2903           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    2904           0 :   if (!quotaManager) {
    2905           0 :     NS_ERROR("Null quota manager, this shouldn't happen, possible leak!");
    2906             : 
    2907           0 :     ++mRefCnt;
    2908             : 
    2909           0 :     return;
    2910             :   }
    2911             : 
    2912           0 :   MutexAutoLock lock(quotaManager->mQuotaMutex);
    2913             : 
    2914           0 :   ++mRefCnt;
    2915             : }
    2916             : 
    2917             : void
    2918           0 : QuotaObject::Release()
    2919             : {
    2920           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    2921           0 :   if (!quotaManager) {
    2922           0 :     NS_ERROR("Null quota manager, this shouldn't happen, possible leak!");
    2923             : 
    2924           0 :     nsrefcnt count = --mRefCnt;
    2925           0 :     if (count == 0) {
    2926           0 :       mRefCnt = 1;
    2927           0 :       delete this;
    2928             :     }
    2929             : 
    2930           0 :     return;
    2931             :   }
    2932             : 
    2933             :   {
    2934           0 :     MutexAutoLock lock(quotaManager->mQuotaMutex);
    2935             : 
    2936           0 :     --mRefCnt;
    2937             : 
    2938           0 :     if (mRefCnt > 0) {
    2939           0 :       return;
    2940             :     }
    2941             : 
    2942           0 :     if (mOriginInfo) {
    2943           0 :       mOriginInfo->mQuotaObjects.Remove(mPath);
    2944             :     }
    2945             :   }
    2946             : 
    2947           0 :   delete this;
    2948             : }
    2949             : 
    2950             : bool
    2951           0 : QuotaObject::MaybeUpdateSize(int64_t aSize, bool aTruncate)
    2952             : {
    2953           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    2954           0 :   MOZ_ASSERT(quotaManager);
    2955             : 
    2956           0 :   MutexAutoLock lock(quotaManager->mQuotaMutex);
    2957             : 
    2958           0 :   if (mQuotaCheckDisabled) {
    2959           0 :     return true;
    2960             :   }
    2961             : 
    2962           0 :   if (mSize == aSize) {
    2963           0 :     return true;
    2964             :   }
    2965             : 
    2966           0 :   if (!mOriginInfo) {
    2967           0 :     mSize = aSize;
    2968           0 :     return true;
    2969             :   }
    2970             : 
    2971           0 :   GroupInfo* groupInfo = mOriginInfo->mGroupInfo;
    2972           0 :   MOZ_ASSERT(groupInfo);
    2973             : 
    2974           0 :   if (mSize > aSize) {
    2975           0 :     if (aTruncate) {
    2976           0 :       const int64_t delta = mSize - aSize;
    2977             : 
    2978           0 :       AssertNoUnderflow(quotaManager->mTemporaryStorageUsage, delta);
    2979           0 :       quotaManager->mTemporaryStorageUsage -= delta;
    2980             : 
    2981           0 :       if (!mOriginInfo->LockedPersisted()) {
    2982           0 :         AssertNoUnderflow(groupInfo->mUsage, delta);
    2983           0 :         groupInfo->mUsage -= delta;
    2984             :       }
    2985             : 
    2986           0 :       AssertNoUnderflow(mOriginInfo->mUsage, delta);
    2987           0 :       mOriginInfo->mUsage -= delta;
    2988             : 
    2989           0 :       mSize = aSize;
    2990             :     }
    2991           0 :     return true;
    2992             :   }
    2993             : 
    2994           0 :   MOZ_ASSERT(mSize < aSize);
    2995             : 
    2996             :   RefPtr<GroupInfo> complementaryGroupInfo =
    2997           0 :     groupInfo->mGroupInfoPair->LockedGetGroupInfo(
    2998           0 :       ComplementaryPersistenceType(groupInfo->mPersistenceType));
    2999             : 
    3000           0 :   uint64_t delta = aSize - mSize;
    3001             : 
    3002           0 :   AssertNoOverflow(mOriginInfo->mUsage, delta);
    3003           0 :   uint64_t newUsage = mOriginInfo->mUsage + delta;
    3004             : 
    3005             :   // Temporary storage has no limit for origin usage (there's a group and the
    3006             :   // global limit though).
    3007             : 
    3008           0 :   uint64_t newGroupUsage = groupInfo->mUsage;
    3009           0 :   if (!mOriginInfo->LockedPersisted()) {
    3010           0 :     AssertNoOverflow(groupInfo->mUsage, delta);
    3011           0 :     newGroupUsage += delta;
    3012             : 
    3013           0 :     uint64_t groupUsage = groupInfo->mUsage;
    3014           0 :     if (complementaryGroupInfo) {
    3015           0 :       AssertNoOverflow(groupUsage, complementaryGroupInfo->mUsage);
    3016           0 :       groupUsage += complementaryGroupInfo->mUsage;
    3017             :     }
    3018             : 
    3019             :     // Temporary storage has a hard limit for group usage (20 % of the global
    3020             :     // limit).
    3021           0 :     AssertNoOverflow(groupUsage, delta);
    3022           0 :     if (groupUsage + delta > quotaManager->GetGroupLimit()) {
    3023           0 :       return false;
    3024             :     }
    3025             :   }
    3026             : 
    3027           0 :   AssertNoOverflow(quotaManager->mTemporaryStorageUsage, delta);
    3028           0 :   uint64_t newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage +
    3029           0 :                                       delta;
    3030             : 
    3031           0 :   if (newTemporaryStorageUsage > quotaManager->mTemporaryStorageLimit) {
    3032             :     // This will block the thread without holding the lock while waitting.
    3033             : 
    3034           0 :     AutoTArray<RefPtr<DirectoryLockImpl>, 10> locks;
    3035             : 
    3036             :     uint64_t sizeToBeFreed =
    3037           0 :       quotaManager->LockedCollectOriginsForEviction(delta, locks);
    3038             : 
    3039           0 :     if (!sizeToBeFreed) {
    3040           0 :       MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
    3041             : 
    3042             :       // Notify pressure event.
    3043             :       RefPtr<StoragePressureRunnable> storagePressureRunnable =
    3044           0 :         new StoragePressureRunnable(quotaManager->mTemporaryStorageUsage);
    3045             : 
    3046           0 :       MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(storagePressureRunnable));
    3047             : 
    3048           0 :       return false;
    3049             :     }
    3050             : 
    3051           0 :     NS_ASSERTION(sizeToBeFreed >= delta, "Huh?");
    3052             : 
    3053             :     {
    3054           0 :       MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
    3055             : 
    3056           0 :       for (RefPtr<DirectoryLockImpl>& lock : locks) {
    3057           0 :         MOZ_ASSERT(!lock->GetPersistenceType().IsNull());
    3058           0 :         MOZ_ASSERT(lock->GetOriginScope().IsOrigin());
    3059           0 :         MOZ_ASSERT(!lock->GetOriginScope().GetOrigin().IsEmpty());
    3060             : 
    3061           0 :         quotaManager->DeleteFilesForOrigin(lock->GetPersistenceType().Value(),
    3062           0 :                                            lock->GetOriginScope().GetOrigin());
    3063             :       }
    3064             :     }
    3065             : 
    3066             :     // Relocked.
    3067             : 
    3068           0 :     NS_ASSERTION(mOriginInfo, "How come?!");
    3069             : 
    3070           0 :     for (DirectoryLockImpl* lock : locks) {
    3071           0 :       MOZ_ASSERT(!lock->GetPersistenceType().IsNull());
    3072           0 :       MOZ_ASSERT(!lock->GetGroup().IsEmpty());
    3073           0 :       MOZ_ASSERT(lock->GetOriginScope().IsOrigin());
    3074           0 :       MOZ_ASSERT(!lock->GetOriginScope().GetOrigin().IsEmpty());
    3075           0 :       MOZ_ASSERT(lock->GetOriginScope().GetOrigin() != mOriginInfo->mOrigin,
    3076             :                  "Deleted itself!");
    3077             : 
    3078           0 :       quotaManager->LockedRemoveQuotaForOrigin(
    3079           0 :                                              lock->GetPersistenceType().Value(),
    3080             :                                              lock->GetGroup(),
    3081           0 :                                              lock->GetOriginScope().GetOrigin());
    3082             :     }
    3083             : 
    3084             :     // We unlocked and relocked several times so we need to recompute all the
    3085             :     // essential variables and recheck the group limit.
    3086             : 
    3087           0 :     AssertNoUnderflow(aSize, mSize);
    3088           0 :     delta = aSize - mSize;
    3089             : 
    3090           0 :     AssertNoOverflow(mOriginInfo->mUsage, delta);
    3091           0 :     newUsage = mOriginInfo->mUsage + delta;
    3092             : 
    3093           0 :     newGroupUsage = groupInfo->mUsage;
    3094           0 :     if (!mOriginInfo->LockedPersisted()) {
    3095           0 :       AssertNoOverflow(groupInfo->mUsage, delta);
    3096           0 :       newGroupUsage += delta;
    3097             : 
    3098           0 :       uint64_t groupUsage = groupInfo->mUsage;
    3099           0 :       if (complementaryGroupInfo) {
    3100           0 :         AssertNoOverflow(groupUsage, complementaryGroupInfo->mUsage);
    3101           0 :         groupUsage += complementaryGroupInfo->mUsage;
    3102             :       }
    3103             : 
    3104           0 :       AssertNoOverflow(groupUsage, delta);
    3105           0 :       if (groupUsage + delta > quotaManager->GetGroupLimit()) {
    3106             :         // Unfortunately some other thread increased the group usage in the
    3107             :         // meantime and we are not below the group limit anymore.
    3108             : 
    3109             :         // However, the origin eviction must be finalized in this case too.
    3110           0 :         MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
    3111             : 
    3112           0 :         quotaManager->FinalizeOriginEviction(locks);
    3113             : 
    3114           0 :         return false;
    3115             :       }
    3116             :     }
    3117             : 
    3118           0 :     AssertNoOverflow(quotaManager->mTemporaryStorageUsage, delta);
    3119           0 :     newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage + delta;
    3120             : 
    3121           0 :     NS_ASSERTION(newTemporaryStorageUsage <=
    3122             :                  quotaManager->mTemporaryStorageLimit, "How come?!");
    3123             : 
    3124             :     // Ok, we successfully freed enough space and the operation can continue
    3125             :     // without throwing the quota error.
    3126           0 :     mOriginInfo->mUsage = newUsage;
    3127           0 :     if (!mOriginInfo->LockedPersisted()) {
    3128           0 :       groupInfo->mUsage = newGroupUsage;
    3129             :     }
    3130           0 :     quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;;
    3131             : 
    3132             :     // Some other thread could increase the size in the meantime, but no more
    3133             :     // than this one.
    3134           0 :     MOZ_ASSERT(mSize < aSize);
    3135           0 :     mSize = aSize;
    3136             : 
    3137             :     // Finally, release IO thread only objects and allow next synchronized
    3138             :     // ops for the evicted origins.
    3139           0 :     MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
    3140             : 
    3141           0 :     quotaManager->FinalizeOriginEviction(locks);
    3142             : 
    3143           0 :     return true;
    3144             :   }
    3145             : 
    3146           0 :   mOriginInfo->mUsage = newUsage;
    3147           0 :   if (!mOriginInfo->LockedPersisted()) {
    3148           0 :     groupInfo->mUsage = newGroupUsage;
    3149             :   }
    3150           0 :   quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;
    3151             : 
    3152           0 :   mSize = aSize;
    3153             : 
    3154           0 :   return true;
    3155             : }
    3156             : 
    3157             : void
    3158           0 : QuotaObject::DisableQuotaCheck()
    3159             : {
    3160           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    3161           0 :   MOZ_ASSERT(quotaManager);
    3162             : 
    3163           0 :   MutexAutoLock lock(quotaManager->mQuotaMutex);
    3164             : 
    3165           0 :   mQuotaCheckDisabled = true;
    3166           0 : }
    3167             : 
    3168             : void
    3169           0 : QuotaObject::EnableQuotaCheck()
    3170             : {
    3171           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    3172           0 :   MOZ_ASSERT(quotaManager);
    3173             : 
    3174           0 :   MutexAutoLock lock(quotaManager->mQuotaMutex);
    3175             : 
    3176           0 :   mQuotaCheckDisabled = false;
    3177           0 : }
    3178             : 
    3179             : /*******************************************************************************
    3180             :  * Quota manager
    3181             :  ******************************************************************************/
    3182             : 
    3183           0 : QuotaManager::QuotaManager()
    3184             : : mQuotaMutex("QuotaManager.mQuotaMutex"),
    3185             :   mTemporaryStorageLimit(0),
    3186             :   mTemporaryStorageUsage(0),
    3187             :   mTemporaryStorageInitialized(false),
    3188           0 :   mStorageInitialized(false)
    3189             : {
    3190           0 :   AssertIsOnOwningThread();
    3191           0 :   MOZ_ASSERT(!gInstance);
    3192           0 : }
    3193             : 
    3194           0 : QuotaManager::~QuotaManager()
    3195             : {
    3196           0 :   AssertIsOnOwningThread();
    3197           0 :   MOZ_ASSERT(!gInstance || gInstance == this);
    3198           0 : }
    3199             : 
    3200             : void
    3201           0 : QuotaManager::GetOrCreate(nsIRunnable* aCallback)
    3202             : {
    3203           0 :   AssertIsOnBackgroundThread();
    3204             : 
    3205           0 :   if (IsShuttingDown()) {
    3206           0 :     MOZ_ASSERT(false, "Calling GetOrCreate() after shutdown!");
    3207             :     return;
    3208             :   }
    3209             : 
    3210           0 :   if (gInstance || gCreateFailed) {
    3211           0 :     MOZ_ASSERT(!gCreateRunnable);
    3212           0 :     MOZ_ASSERT_IF(gCreateFailed, !gInstance);
    3213             : 
    3214           0 :     MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(aCallback));
    3215             :   } else {
    3216           0 :     if (!gCreateRunnable) {
    3217           0 :       gCreateRunnable = new CreateRunnable();
    3218           0 :       MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(gCreateRunnable));
    3219             :     }
    3220             : 
    3221           0 :     gCreateRunnable->AddCallback(aCallback);
    3222             :   }
    3223           0 : }
    3224             : 
    3225             : // static
    3226             : QuotaManager*
    3227           1 : QuotaManager::Get()
    3228             : {
    3229             :   // Does not return an owning reference.
    3230           1 :   return gInstance;
    3231             : }
    3232             : 
    3233             : // static
    3234             : bool
    3235           0 : QuotaManager::IsShuttingDown()
    3236             : {
    3237           0 :   return gShutdown;
    3238             : }
    3239             : 
    3240             : auto
    3241           0 : QuotaManager::CreateDirectoryLock(const Nullable<PersistenceType>& aPersistenceType,
    3242             :                                   const nsACString& aGroup,
    3243             :                                   const OriginScope& aOriginScope,
    3244             :                                   const Nullable<Client::Type>& aClientType,
    3245             :                                   bool aExclusive,
    3246             :                                   bool aInternal,
    3247             :                                   OpenDirectoryListener* aOpenListener)
    3248             :   -> already_AddRefed<DirectoryLockImpl>
    3249             : {
    3250           0 :   AssertIsOnOwningThread();
    3251           0 :   MOZ_ASSERT_IF(aOriginScope.IsOrigin(), !aOriginScope.GetOrigin().IsEmpty());
    3252           0 :   MOZ_ASSERT_IF(!aInternal, !aPersistenceType.IsNull());
    3253           0 :   MOZ_ASSERT_IF(!aInternal,
    3254             :                 aPersistenceType.Value() != PERSISTENCE_TYPE_INVALID);
    3255           0 :   MOZ_ASSERT_IF(!aInternal, !aGroup.IsEmpty());
    3256           0 :   MOZ_ASSERT_IF(!aInternal, aOriginScope.IsOrigin());
    3257           0 :   MOZ_ASSERT_IF(!aInternal, !aClientType.IsNull());
    3258           0 :   MOZ_ASSERT_IF(!aInternal, aClientType.Value() != Client::TYPE_MAX);
    3259           0 :   MOZ_ASSERT_IF(!aInternal, aOpenListener);
    3260             : 
    3261             :   RefPtr<DirectoryLockImpl> lock = new DirectoryLockImpl(this,
    3262             :                                                            aPersistenceType,
    3263             :                                                            aGroup,
    3264             :                                                            aOriginScope,
    3265             :                                                            aClientType,
    3266             :                                                            aExclusive,
    3267             :                                                            aInternal,
    3268           0 :                                                            aOpenListener);
    3269             : 
    3270           0 :   mPendingDirectoryLocks.AppendElement(lock);
    3271             : 
    3272             :   // See if this lock needs to wait.
    3273           0 :   bool blocked = false;
    3274           0 :   for (uint32_t index = mDirectoryLocks.Length(); index > 0; index--) {
    3275           0 :     DirectoryLockImpl* existingLock = mDirectoryLocks[index - 1];
    3276           0 :     if (lock->MustWaitFor(*existingLock)) {
    3277           0 :       existingLock->AddBlockingLock(lock);
    3278           0 :       lock->AddBlockedOnLock(existingLock);
    3279           0 :       blocked = true;
    3280             :     }
    3281             :   }
    3282             : 
    3283           0 :   RegisterDirectoryLock(lock);
    3284             : 
    3285             :   // Otherwise, notify the open listener immediately.
    3286           0 :   if (!blocked) {
    3287           0 :     lock->NotifyOpenListener();
    3288             :   }
    3289             : 
    3290           0 :   return lock.forget();
    3291             : }
    3292             : 
    3293             : auto
    3294           0 : QuotaManager::CreateDirectoryLockForEviction(PersistenceType aPersistenceType,
    3295             :                                              const nsACString& aGroup,
    3296             :                                              const nsACString& aOrigin)
    3297             :   -> already_AddRefed<DirectoryLockImpl>
    3298             : {
    3299           0 :   AssertIsOnOwningThread();
    3300           0 :   MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_INVALID);
    3301           0 :   MOZ_ASSERT(!aOrigin.IsEmpty());
    3302             : 
    3303             :   RefPtr<DirectoryLockImpl> lock =
    3304             :     new DirectoryLockImpl(this,
    3305           0 :                           Nullable<PersistenceType>(aPersistenceType),
    3306             :                           aGroup,
    3307           0 :                           OriginScope::FromOrigin(aOrigin),
    3308           0 :                           Nullable<Client::Type>(),
    3309             :                           /* aExclusive */ true,
    3310             :                           /* aInternal */ true,
    3311           0 :                           nullptr);
    3312             : 
    3313             : #ifdef DEBUG
    3314           0 :   for (uint32_t index = mDirectoryLocks.Length(); index > 0; index--) {
    3315           0 :     DirectoryLockImpl* existingLock = mDirectoryLocks[index - 1];
    3316           0 :     MOZ_ASSERT(!lock->MustWaitFor(*existingLock));
    3317             :   }
    3318             : #endif
    3319             : 
    3320           0 :   RegisterDirectoryLock(lock);
    3321             : 
    3322           0 :   return lock.forget();
    3323             : }
    3324             : 
    3325             : void
    3326           0 : QuotaManager::RegisterDirectoryLock(DirectoryLockImpl* aLock)
    3327             : {
    3328           0 :   AssertIsOnOwningThread();
    3329           0 :   MOZ_ASSERT(aLock);
    3330             : 
    3331           0 :   mDirectoryLocks.AppendElement(aLock);
    3332             : 
    3333           0 :   if (aLock->ShouldUpdateLockTable()) {
    3334             :     const Nullable<PersistenceType>& persistenceType =
    3335           0 :       aLock->GetPersistenceType();
    3336           0 :     const OriginScope& originScope = aLock->GetOriginScope();
    3337             : 
    3338           0 :     MOZ_ASSERT(!persistenceType.IsNull());
    3339           0 :     MOZ_ASSERT(!aLock->GetGroup().IsEmpty());
    3340           0 :     MOZ_ASSERT(originScope.IsOrigin());
    3341           0 :     MOZ_ASSERT(!originScope.GetOrigin().IsEmpty());
    3342             : 
    3343             :     DirectoryLockTable& directoryLockTable =
    3344           0 :       GetDirectoryLockTable(persistenceType.Value());
    3345             : 
    3346             :     nsTArray<DirectoryLockImpl*>* array;
    3347           0 :     if (!directoryLockTable.Get(originScope.GetOrigin(), &array)) {
    3348           0 :       array = new nsTArray<DirectoryLockImpl*>();
    3349           0 :       directoryLockTable.Put(originScope.GetOrigin(), array);
    3350             : 
    3351           0 :       if (!IsShuttingDown()) {
    3352           0 :         UpdateOriginAccessTime(persistenceType.Value(),
    3353             :                                aLock->GetGroup(),
    3354           0 :                                originScope.GetOrigin());
    3355             :       }
    3356             :     }
    3357           0 :     array->AppendElement(aLock);
    3358             :   }
    3359           0 : }
    3360             : 
    3361             : void
    3362           0 : QuotaManager::UnregisterDirectoryLock(DirectoryLockImpl* aLock)
    3363             : {
    3364           0 :   AssertIsOnOwningThread();
    3365             : 
    3366           0 :   MOZ_ALWAYS_TRUE(mDirectoryLocks.RemoveElement(aLock));
    3367             : 
    3368           0 :   if (aLock->ShouldUpdateLockTable()) {
    3369             :     const Nullable<PersistenceType>& persistenceType =
    3370           0 :       aLock->GetPersistenceType();
    3371           0 :     const OriginScope& originScope = aLock->GetOriginScope();
    3372             : 
    3373           0 :     MOZ_ASSERT(!persistenceType.IsNull());
    3374           0 :     MOZ_ASSERT(!aLock->GetGroup().IsEmpty());
    3375           0 :     MOZ_ASSERT(originScope.IsOrigin());
    3376           0 :     MOZ_ASSERT(!originScope.GetOrigin().IsEmpty());
    3377             : 
    3378             :     DirectoryLockTable& directoryLockTable =
    3379           0 :       GetDirectoryLockTable(persistenceType.Value());
    3380             : 
    3381             :     nsTArray<DirectoryLockImpl*>* array;
    3382           0 :     MOZ_ALWAYS_TRUE(directoryLockTable.Get(originScope.GetOrigin(), &array));
    3383             : 
    3384           0 :     MOZ_ALWAYS_TRUE(array->RemoveElement(aLock));
    3385           0 :     if (array->IsEmpty()) {
    3386           0 :       directoryLockTable.Remove(originScope.GetOrigin());
    3387             : 
    3388           0 :       if (!IsShuttingDown()) {
    3389           0 :         UpdateOriginAccessTime(persistenceType.Value(),
    3390             :                                aLock->GetGroup(),
    3391           0 :                                originScope.GetOrigin());
    3392             :       }
    3393             :     }
    3394             :   }
    3395           0 : }
    3396             : 
    3397             : void
    3398           0 : QuotaManager::RemovePendingDirectoryLock(DirectoryLockImpl* aLock)
    3399             : {
    3400           0 :   AssertIsOnOwningThread();
    3401           0 :   MOZ_ASSERT(aLock);
    3402             : 
    3403           0 :   MOZ_ALWAYS_TRUE(mPendingDirectoryLocks.RemoveElement(aLock));
    3404           0 : }
    3405             : 
    3406             : uint64_t
    3407           0 : QuotaManager::CollectOriginsForEviction(
    3408             :                                   uint64_t aMinSizeToBeFreed,
    3409             :                                   nsTArray<RefPtr<DirectoryLockImpl>>& aLocks)
    3410             : {
    3411           0 :   AssertIsOnOwningThread();
    3412           0 :   MOZ_ASSERT(aLocks.IsEmpty());
    3413             : 
    3414             :   struct MOZ_STACK_CLASS Helper final
    3415             :   {
    3416             :     static void
    3417           0 :     GetInactiveOriginInfos(nsTArray<RefPtr<OriginInfo>>& aOriginInfos,
    3418             :                            nsTArray<DirectoryLockImpl*>& aLocks,
    3419             :                            nsTArray<OriginInfo*>& aInactiveOriginInfos)
    3420             :     {
    3421           0 :       for (OriginInfo* originInfo : aOriginInfos) {
    3422           0 :         MOZ_ASSERT(originInfo->mGroupInfo->mPersistenceType !=
    3423             :                      PERSISTENCE_TYPE_PERSISTENT);
    3424             : 
    3425           0 :         if (originInfo->LockedPersisted()) {
    3426           0 :           continue;
    3427             :         }
    3428             : 
    3429           0 :         OriginScope originScope = OriginScope::FromOrigin(originInfo->mOrigin);
    3430             : 
    3431           0 :         bool match = false;
    3432           0 :         for (uint32_t j = aLocks.Length(); j > 0; j--) {
    3433           0 :           DirectoryLockImpl* lock = aLocks[j - 1];
    3434           0 :           if (originScope.Matches(lock->GetOriginScope())) {
    3435           0 :             match = true;
    3436           0 :             break;
    3437             :           }
    3438             :         }
    3439             : 
    3440           0 :         if (!match) {
    3441           0 :           MOZ_ASSERT(!originInfo->mQuotaObjects.Count(),
    3442             :                      "Inactive origin shouldn't have open files!");
    3443           0 :           aInactiveOriginInfos.InsertElementSorted(originInfo,
    3444           0 :                                                    OriginInfoLRUComparator());
    3445             :         }
    3446             :       }
    3447           0 :     }
    3448             :   };
    3449             : 
    3450             :   // Split locks into separate arrays and filter out locks for persistent
    3451             :   // storage, they can't block us.
    3452           0 :   nsTArray<DirectoryLockImpl*> temporaryStorageLocks;
    3453           0 :   nsTArray<DirectoryLockImpl*> defaultStorageLocks;
    3454           0 :   for (DirectoryLockImpl* lock : mDirectoryLocks) {
    3455             :     const Nullable<PersistenceType>& persistenceType =
    3456           0 :       lock->GetPersistenceType();
    3457             : 
    3458           0 :     if (persistenceType.IsNull()) {
    3459           0 :       temporaryStorageLocks.AppendElement(lock);
    3460           0 :       defaultStorageLocks.AppendElement(lock);
    3461           0 :     } else if (persistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY) {
    3462           0 :       temporaryStorageLocks.AppendElement(lock);
    3463           0 :     } else if (persistenceType.Value() == PERSISTENCE_TYPE_DEFAULT) {
    3464           0 :       defaultStorageLocks.AppendElement(lock);
    3465             :     } else {
    3466           0 :       MOZ_ASSERT(persistenceType.Value() == PERSISTENCE_TYPE_PERSISTENT);
    3467             : 
    3468             :       // Do nothing here, persistent origins don't need to be collected ever.
    3469             :     }
    3470             :   }
    3471             : 
    3472           0 :   nsTArray<OriginInfo*> inactiveOrigins;
    3473             : 
    3474             :   // Enumerate and process inactive origins. This must be protected by the
    3475             :   // mutex.
    3476           0 :   MutexAutoLock lock(mQuotaMutex);
    3477             : 
    3478           0 :   for (auto iter = mGroupInfoPairs.Iter(); !iter.Done(); iter.Next()) {
    3479           0 :     GroupInfoPair* pair = iter.UserData();
    3480             : 
    3481           0 :     MOZ_ASSERT(!iter.Key().IsEmpty());
    3482           0 :     MOZ_ASSERT(pair);
    3483             : 
    3484             :     RefPtr<GroupInfo> groupInfo =
    3485           0 :       pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
    3486           0 :     if (groupInfo) {
    3487           0 :       Helper::GetInactiveOriginInfos(groupInfo->mOriginInfos,
    3488             :                                      temporaryStorageLocks,
    3489           0 :                                      inactiveOrigins);
    3490             :     }
    3491             : 
    3492           0 :     groupInfo = pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
    3493           0 :     if (groupInfo) {
    3494           0 :       Helper::GetInactiveOriginInfos(groupInfo->mOriginInfos,
    3495             :                                      defaultStorageLocks,
    3496           0 :                                      inactiveOrigins);
    3497             :     }
    3498             :   }
    3499             : 
    3500             : #ifdef DEBUG
    3501             :   // Make sure the array is sorted correctly.
    3502           0 :   for (uint32_t index = inactiveOrigins.Length(); index > 1; index--) {
    3503           0 :     MOZ_ASSERT(inactiveOrigins[index - 1]->mAccessTime >=
    3504             :                inactiveOrigins[index - 2]->mAccessTime);
    3505             :   }
    3506             : #endif
    3507             : 
    3508             :   // Create a list of inactive and the least recently used origins
    3509             :   // whose aggregate size is greater or equals the minimal size to be freed.
    3510           0 :   uint64_t sizeToBeFreed = 0;
    3511           0 :   for(uint32_t count = inactiveOrigins.Length(), index = 0;
    3512           0 :       index < count;
    3513             :       index++) {
    3514           0 :     if (sizeToBeFreed >= aMinSizeToBeFreed) {
    3515           0 :       inactiveOrigins.TruncateLength(index);
    3516           0 :       break;
    3517             :     }
    3518             : 
    3519           0 :     sizeToBeFreed += inactiveOrigins[index]->mUsage;
    3520             :   }
    3521             : 
    3522           0 :   if (sizeToBeFreed >= aMinSizeToBeFreed) {
    3523             :     // Success, add directory locks for these origins, so any other
    3524             :     // operations for them will be delayed (until origin eviction is finalized).
    3525             : 
    3526           0 :     for (OriginInfo* originInfo : inactiveOrigins) {
    3527             :       RefPtr<DirectoryLockImpl> lock =
    3528           0 :         CreateDirectoryLockForEviction(originInfo->mGroupInfo->mPersistenceType,
    3529           0 :                                        originInfo->mGroupInfo->mGroup,
    3530           0 :                                        originInfo->mOrigin);
    3531           0 :       aLocks.AppendElement(lock.forget());
    3532             :     }
    3533             : 
    3534           0 :     return sizeToBeFreed;
    3535             :   }
    3536             : 
    3537           0 :   return 0;
    3538             : }
    3539             : 
    3540             : nsresult
    3541           0 : QuotaManager::Init(const nsAString& aBasePath)
    3542             : {
    3543             :   nsresult rv;
    3544             : 
    3545           0 :   mBasePath = aBasePath;
    3546             : 
    3547           0 :   nsCOMPtr<nsIFile> baseDir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    3548           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3549           0 :     return rv;
    3550             :   }
    3551             : 
    3552           0 :   rv = baseDir->InitWithPath(aBasePath);
    3553           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3554           0 :     return rv;
    3555             :   }
    3556             : 
    3557           0 :   rv = CloneStoragePath(baseDir,
    3558           0 :                         NS_LITERAL_STRING(INDEXEDDB_DIRECTORY_NAME),
    3559           0 :                         mIndexedDBPath);
    3560           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3561           0 :     return rv;
    3562             :   }
    3563             : 
    3564           0 :   rv = baseDir->Append(NS_LITERAL_STRING(STORAGE_DIRECTORY_NAME));
    3565           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3566           0 :     return rv;
    3567             :   }
    3568             : 
    3569           0 :   rv = baseDir->GetPath(mStoragePath);
    3570           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3571           0 :     return rv;
    3572             :   }
    3573             : 
    3574           0 :   rv = CloneStoragePath(baseDir,
    3575           0 :                         NS_LITERAL_STRING(PERMANENT_DIRECTORY_NAME),
    3576           0 :                         mPermanentStoragePath);
    3577           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3578           0 :     return rv;
    3579             :   }
    3580             : 
    3581           0 :   rv = CloneStoragePath(baseDir,
    3582           0 :                         NS_LITERAL_STRING(TEMPORARY_DIRECTORY_NAME),
    3583           0 :                         mTemporaryStoragePath);
    3584           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3585           0 :     return rv;
    3586             :   }
    3587             : 
    3588           0 :   rv = CloneStoragePath(baseDir,
    3589           0 :                         NS_LITERAL_STRING(DEFAULT_DIRECTORY_NAME),
    3590           0 :                         mDefaultStoragePath);
    3591           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3592           0 :     return rv;
    3593             :   }
    3594             : 
    3595             :   // Make a lazy thread for any IO we need (like clearing or enumerating the
    3596             :   // contents of storage directories).
    3597             :   mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
    3598           0 :                                  NS_LITERAL_CSTRING("Storage I/O"),
    3599           0 :                                  LazyIdleThread::ManualShutdown);
    3600             : 
    3601             :   // Make a timer here to avoid potential failures later. We don't actually
    3602             :   // initialize the timer until shutdown.
    3603           0 :   mShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
    3604           0 :   if (NS_WARN_IF(!mShutdownTimer)) {
    3605           0 :     return NS_ERROR_FAILURE;
    3606             :   }
    3607             : 
    3608             :   static_assert(Client::IDB == 0 && Client::ASMJS == 1 && Client::DOMCACHE == 2 &&
    3609             :                 Client::TYPE_MAX == 3, "Fix the registration!");
    3610             : 
    3611           0 :   MOZ_ASSERT(mClients.Capacity() == Client::TYPE_MAX,
    3612             :              "Should be using an auto array with correct capacity!");
    3613             : 
    3614             :   // Register clients.
    3615           0 :   mClients.AppendElement(indexedDB::CreateQuotaClient());
    3616           0 :   mClients.AppendElement(asmjscache::CreateClient());
    3617           0 :   mClients.AppendElement(cache::CreateQuotaClient());
    3618             : 
    3619           0 :   return NS_OK;
    3620             : }
    3621             : 
    3622             : void
    3623           0 : QuotaManager::Shutdown()
    3624             : {
    3625           0 :   AssertIsOnOwningThread();
    3626             : 
    3627             :   // Setting this flag prevents the service from being recreated and prevents
    3628             :   // further storagess from being created.
    3629           0 :   if (gShutdown.exchange(true)) {
    3630           0 :     NS_ERROR("Shutdown more than once?!");
    3631             :   }
    3632             : 
    3633           0 :   StopIdleMaintenance();
    3634             : 
    3635             :   // Kick off the shutdown timer.
    3636           0 :   MOZ_ALWAYS_SUCCEEDS(
    3637             :     mShutdownTimer->InitWithNamedFuncCallback(&ShutdownTimerCallback,
    3638             :                                               this,
    3639             :                                               DEFAULT_SHUTDOWN_TIMER_MS,
    3640             :                                               nsITimer::TYPE_ONE_SHOT,
    3641             :                                               "QuotaManager::ShutdownTimerCallback"));
    3642             : 
    3643             :   // Each client will spin the event loop while we wait on all the threads
    3644             :   // to close. Our timer may fire during that loop.
    3645           0 :   for (uint32_t index = 0; index < Client::TYPE_MAX; index++) {
    3646           0 :     mClients[index]->ShutdownWorkThreads();
    3647             :   }
    3648             : 
    3649             :   // Cancel the timer regardless of whether it actually fired.
    3650           0 :   if (NS_FAILED(mShutdownTimer->Cancel())) {
    3651           0 :     NS_WARNING("Failed to cancel shutdown timer!");
    3652             :   }
    3653             : 
    3654             :   // NB: It's very important that runnable is destroyed on this thread
    3655             :   // (i.e. after we join the IO thread) because we can't release the
    3656             :   // QuotaManager on the IO thread. This should probably use
    3657             :   // NewNonOwningRunnableMethod ...
    3658             :   RefPtr<Runnable> runnable =
    3659           0 :     NewRunnableMethod("dom::quota::QuotaManager::ReleaseIOThreadObjects",
    3660             :                       this,
    3661           0 :                       &QuotaManager::ReleaseIOThreadObjects);
    3662           0 :   MOZ_ASSERT(runnable);
    3663             : 
    3664             :   // Give clients a chance to cleanup IO thread only objects.
    3665           0 :   if (NS_FAILED(mIOThread->Dispatch(runnable, NS_DISPATCH_NORMAL))) {
    3666           0 :     NS_WARNING("Failed to dispatch runnable!");
    3667             :   }
    3668             : 
    3669             :   // Make sure to join with our IO thread.
    3670           0 :   if (NS_FAILED(mIOThread->Shutdown())) {
    3671           0 :     NS_WARNING("Failed to shutdown IO thread!");
    3672             :   }
    3673             : 
    3674           0 :   for (RefPtr<DirectoryLockImpl>& lock : mPendingDirectoryLocks) {
    3675           0 :     lock->Invalidate();
    3676             :   }
    3677           0 : }
    3678             : 
    3679             : void
    3680           0 : QuotaManager::InitQuotaForOrigin(PersistenceType aPersistenceType,
    3681             :                                  const nsACString& aGroup,
    3682             :                                  const nsACString& aOrigin,
    3683             :                                  uint64_t aUsageBytes,
    3684             :                                  int64_t aAccessTime,
    3685             :                                  bool aPersisted)
    3686             : {
    3687           0 :   AssertIsOnIOThread();
    3688           0 :   MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
    3689             : 
    3690           0 :   MutexAutoLock lock(mQuotaMutex);
    3691             : 
    3692             :   GroupInfoPair* pair;
    3693           0 :   if (!mGroupInfoPairs.Get(aGroup, &pair)) {
    3694           0 :     pair = new GroupInfoPair();
    3695           0 :     mGroupInfoPairs.Put(aGroup, pair);
    3696             :     // The hashtable is now responsible to delete the GroupInfoPair.
    3697             :   }
    3698             : 
    3699           0 :   RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
    3700           0 :   if (!groupInfo) {
    3701           0 :     groupInfo = new GroupInfo(pair, aPersistenceType, aGroup);
    3702           0 :     pair->LockedSetGroupInfo(aPersistenceType, groupInfo);
    3703             :   }
    3704             : 
    3705             :   RefPtr<OriginInfo> originInfo =
    3706           0 :     new OriginInfo(groupInfo, aOrigin, aUsageBytes, aAccessTime, aPersisted);
    3707           0 :   groupInfo->LockedAddOriginInfo(originInfo);
    3708           0 : }
    3709             : 
    3710             : void
    3711           0 : QuotaManager::DecreaseUsageForOrigin(PersistenceType aPersistenceType,
    3712             :                                      const nsACString& aGroup,
    3713             :                                      const nsACString& aOrigin,
    3714             :                                      int64_t aSize)
    3715             : {
    3716           0 :   MOZ_ASSERT(!NS_IsMainThread());
    3717           0 :   MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
    3718             : 
    3719           0 :   MutexAutoLock lock(mQuotaMutex);
    3720             : 
    3721             :   GroupInfoPair* pair;
    3722           0 :   if (!mGroupInfoPairs.Get(aGroup, &pair)) {
    3723           0 :     return;
    3724             :   }
    3725             : 
    3726           0 :   RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
    3727           0 :   if (!groupInfo) {
    3728           0 :     return;
    3729             :   }
    3730             : 
    3731           0 :   RefPtr<OriginInfo> originInfo = groupInfo->LockedGetOriginInfo(aOrigin);
    3732           0 :   if (originInfo) {
    3733           0 :     originInfo->LockedDecreaseUsage(aSize);
    3734             :   }
    3735             : }
    3736             : 
    3737             : void
    3738           0 : QuotaManager::UpdateOriginAccessTime(PersistenceType aPersistenceType,
    3739             :                                      const nsACString& aGroup,
    3740             :                                      const nsACString& aOrigin)
    3741             : {
    3742           0 :   AssertIsOnOwningThread();
    3743           0 :   MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
    3744             : 
    3745           0 :   MutexAutoLock lock(mQuotaMutex);
    3746             : 
    3747             :   GroupInfoPair* pair;
    3748           0 :   if (!mGroupInfoPairs.Get(aGroup, &pair)) {
    3749           0 :     return;
    3750             :   }
    3751             : 
    3752           0 :   RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
    3753           0 :   if (!groupInfo) {
    3754           0 :     return;
    3755             :   }
    3756             : 
    3757           0 :   RefPtr<OriginInfo> originInfo = groupInfo->LockedGetOriginInfo(aOrigin);
    3758           0 :   if (originInfo) {
    3759           0 :     int64_t timestamp = PR_Now();
    3760           0 :     originInfo->LockedUpdateAccessTime(timestamp);
    3761             : 
    3762           0 :     MutexAutoUnlock autoUnlock(mQuotaMutex);
    3763             : 
    3764             :     RefPtr<SaveOriginAccessTimeOp> op =
    3765           0 :       new SaveOriginAccessTimeOp(aPersistenceType, aOrigin, timestamp);
    3766             : 
    3767           0 :     op->RunImmediately();
    3768             :   }
    3769             : }
    3770             : 
    3771             : void
    3772           0 : QuotaManager::RemoveQuota()
    3773             : {
    3774           0 :   AssertIsOnIOThread();
    3775             : 
    3776           0 :   MutexAutoLock lock(mQuotaMutex);
    3777             : 
    3778           0 :   for (auto iter = mGroupInfoPairs.Iter(); !iter.Done(); iter.Next()) {
    3779           0 :     nsAutoPtr<GroupInfoPair>& pair = iter.Data();
    3780             : 
    3781           0 :     MOZ_ASSERT(!iter.Key().IsEmpty(), "Empty key!");
    3782           0 :     MOZ_ASSERT(pair, "Null pointer!");
    3783             : 
    3784             :     RefPtr<GroupInfo> groupInfo =
    3785           0 :       pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
    3786           0 :     if (groupInfo) {
    3787           0 :       groupInfo->LockedRemoveOriginInfos();
    3788             :     }
    3789             : 
    3790           0 :     groupInfo = pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
    3791           0 :     if (groupInfo) {
    3792           0 :       groupInfo->LockedRemoveOriginInfos();
    3793             :     }
    3794             : 
    3795           0 :     iter.Remove();
    3796             :   }
    3797             : 
    3798           0 :   NS_ASSERTION(mTemporaryStorageUsage == 0, "Should be zero!");
    3799           0 : }
    3800             : 
    3801             : already_AddRefed<QuotaObject>
    3802           0 : QuotaManager::GetQuotaObject(PersistenceType aPersistenceType,
    3803             :                              const nsACString& aGroup,
    3804             :                              const nsACString& aOrigin,
    3805             :                              nsIFile* aFile)
    3806             : {
    3807           0 :   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
    3808             : 
    3809           0 :   if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
    3810           0 :     return nullptr;
    3811             :   }
    3812             : 
    3813           0 :   nsString path;
    3814           0 :   nsresult rv = aFile->GetPath(path);
    3815           0 :   NS_ENSURE_SUCCESS(rv, nullptr);
    3816             : 
    3817             :   int64_t fileSize;
    3818             : 
    3819             :   bool exists;
    3820           0 :   rv = aFile->Exists(&exists);
    3821           0 :   NS_ENSURE_SUCCESS(rv, nullptr);
    3822             : 
    3823           0 :   if (exists) {
    3824           0 :     rv = aFile->GetFileSize(&fileSize);
    3825           0 :     NS_ENSURE_SUCCESS(rv, nullptr);
    3826             :   }
    3827             :   else {
    3828           0 :     fileSize = 0;
    3829             :   }
    3830             : 
    3831             :   // Re-escape our parameters above to make sure we get the right quota group.
    3832           0 :   nsAutoCString group;
    3833           0 :   rv = NS_EscapeURL(aGroup, esc_Query, group, fallible);
    3834           0 :   NS_ENSURE_SUCCESS(rv, nullptr);
    3835             : 
    3836           0 :   nsAutoCString origin;
    3837           0 :   rv = NS_EscapeURL(aOrigin, esc_Query, origin, fallible);
    3838           0 :   NS_ENSURE_SUCCESS(rv, nullptr);
    3839             : 
    3840           0 :   RefPtr<QuotaObject> result;
    3841             :   {
    3842           0 :     MutexAutoLock lock(mQuotaMutex);
    3843             : 
    3844             :     GroupInfoPair* pair;
    3845           0 :     if (!mGroupInfoPairs.Get(group, &pair)) {
    3846           0 :       return nullptr;
    3847             :     }
    3848             : 
    3849             :     RefPtr<GroupInfo> groupInfo =
    3850           0 :       pair->LockedGetGroupInfo(aPersistenceType);
    3851             : 
    3852           0 :     if (!groupInfo) {
    3853           0 :       return nullptr;
    3854             :     }
    3855             : 
    3856           0 :     RefPtr<OriginInfo> originInfo = groupInfo->LockedGetOriginInfo(origin);
    3857             : 
    3858           0 :     if (!originInfo) {
    3859           0 :       return nullptr;
    3860             :     }
    3861             : 
    3862             :     // We need this extra raw pointer because we can't assign to the smart
    3863             :     // pointer directly since QuotaObject::AddRef would try to acquire the same
    3864             :     // mutex.
    3865             :     QuotaObject* quotaObject;
    3866           0 :     if (!originInfo->mQuotaObjects.Get(path, &quotaObject)) {
    3867             :       // Create a new QuotaObject.
    3868           0 :       quotaObject = new QuotaObject(originInfo, path, fileSize);
    3869             : 
    3870             :       // Put it to the hashtable. The hashtable is not responsible to delete
    3871             :       // the QuotaObject.
    3872           0 :       originInfo->mQuotaObjects.Put(path, quotaObject);
    3873             :     }
    3874             : 
    3875             :     // Addref the QuotaObject and move the ownership to the result. This must
    3876             :     // happen before we unlock!
    3877           0 :     result = quotaObject->LockedAddRef();
    3878             :   }
    3879             : 
    3880             :   // The caller becomes the owner of the QuotaObject, that is, the caller is
    3881             :   // is responsible to delete it when the last reference is removed.
    3882           0 :   return result.forget();
    3883             : }
    3884             : 
    3885             : already_AddRefed<QuotaObject>
    3886           0 : QuotaManager::GetQuotaObject(PersistenceType aPersistenceType,
    3887             :                              const nsACString& aGroup,
    3888             :                              const nsACString& aOrigin,
    3889             :                              const nsAString& aPath)
    3890             : {
    3891             :   nsresult rv;
    3892           0 :   nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    3893           0 :   NS_ENSURE_SUCCESS(rv, nullptr);
    3894             : 
    3895           0 :   rv = file->InitWithPath(aPath);
    3896           0 :   NS_ENSURE_SUCCESS(rv, nullptr);
    3897             : 
    3898           0 :   return GetQuotaObject(aPersistenceType, aGroup, aOrigin, file);
    3899             : }
    3900             : 
    3901             : Nullable<bool>
    3902           0 : QuotaManager::OriginPersisted(const nsACString& aGroup,
    3903             :                               const nsACString& aOrigin)
    3904             : {
    3905           0 :   AssertIsOnIOThread();
    3906             : 
    3907           0 :   MutexAutoLock lock(mQuotaMutex);
    3908             : 
    3909           0 :   RefPtr<OriginInfo> originInfo = LockedGetOriginInfo(PERSISTENCE_TYPE_DEFAULT,
    3910             :                                                       aGroup,
    3911           0 :                                                       aOrigin);
    3912           0 :   if (originInfo) {
    3913           0 :     return Nullable<bool>(originInfo->LockedPersisted());
    3914             :   }
    3915             : 
    3916           0 :   return Nullable<bool>();
    3917             : }
    3918             : 
    3919             : void
    3920           0 : QuotaManager::PersistOrigin(const nsACString& aGroup,
    3921             :                             const nsACString& aOrigin)
    3922             : {
    3923           0 :   AssertIsOnIOThread();
    3924             : 
    3925           0 :   MutexAutoLock lock(mQuotaMutex);
    3926             : 
    3927           0 :   RefPtr<OriginInfo> originInfo = LockedGetOriginInfo(PERSISTENCE_TYPE_DEFAULT,
    3928             :                                                       aGroup,
    3929           0 :                                                       aOrigin);
    3930           0 :   if (originInfo && !originInfo->LockedPersisted()) {
    3931           0 :     originInfo->LockedPersist();
    3932             :   }
    3933           0 : }
    3934             : 
    3935             : void
    3936           0 : QuotaManager::AbortOperationsForProcess(ContentParentId aContentParentId)
    3937             : {
    3938           0 :   AssertIsOnOwningThread();
    3939             : 
    3940           0 :   for (RefPtr<Client>& client : mClients) {
    3941           0 :     client->AbortOperationsForProcess(aContentParentId);
    3942             :   }
    3943           0 : }
    3944             : 
    3945             : nsresult
    3946           0 : QuotaManager::GetDirectoryForOrigin(PersistenceType aPersistenceType,
    3947             :                                     const nsACString& aASCIIOrigin,
    3948             :                                     nsIFile** aDirectory) const
    3949             : {
    3950             :   nsresult rv;
    3951             :   nsCOMPtr<nsIFile> directory =
    3952           0 :     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    3953           0 :   NS_ENSURE_SUCCESS(rv, rv);
    3954             : 
    3955           0 :   rv = directory->InitWithPath(GetStoragePath(aPersistenceType));
    3956           0 :   NS_ENSURE_SUCCESS(rv, rv);
    3957             : 
    3958           0 :   nsAutoCString originSanitized(aASCIIOrigin);
    3959           0 :   SanitizeOriginString(originSanitized);
    3960             : 
    3961           0 :   rv = directory->Append(NS_ConvertASCIItoUTF16(originSanitized));
    3962           0 :   NS_ENSURE_SUCCESS(rv, rv);
    3963             : 
    3964           0 :   directory.forget(aDirectory);
    3965           0 :   return NS_OK;
    3966             : }
    3967             : 
    3968             : nsresult
    3969           0 : QuotaManager::RestoreDirectoryMetadata2(nsIFile* aDirectory, bool aPersistent)
    3970             : {
    3971           0 :   AssertIsOnIOThread();
    3972           0 :   MOZ_ASSERT(aDirectory);
    3973           0 :   MOZ_ASSERT(mStorageInitialized);
    3974             : 
    3975             :   RefPtr<RestoreDirectoryMetadata2Helper> helper =
    3976           0 :     new RestoreDirectoryMetadata2Helper(aDirectory, aPersistent);
    3977             : 
    3978           0 :   nsresult rv = helper->RestoreMetadata2File();
    3979           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3980           0 :     return rv;
    3981             :   }
    3982             : 
    3983           0 :   return NS_OK;
    3984             : }
    3985             : 
    3986             : nsresult
    3987           0 : QuotaManager::GetDirectoryMetadata2(nsIFile* aDirectory,
    3988             :                                     int64_t* aTimestamp,
    3989             :                                     bool* aPersisted,
    3990             :                                     nsACString& aSuffix,
    3991             :                                     nsACString& aGroup,
    3992             :                                     nsACString& aOrigin)
    3993             : {
    3994           0 :   MOZ_ASSERT(!NS_IsMainThread());
    3995           0 :   MOZ_ASSERT(aDirectory);
    3996           0 :   MOZ_ASSERT(aTimestamp);
    3997           0 :   MOZ_ASSERT(aPersisted);
    3998           0 :   MOZ_ASSERT(mStorageInitialized);
    3999             : 
    4000           0 :   nsCOMPtr<nsIBinaryInputStream> binaryStream;
    4001           0 :   nsresult rv = GetBinaryInputStream(aDirectory,
    4002           0 :                                      NS_LITERAL_STRING(METADATA_V2_FILE_NAME),
    4003           0 :                                      getter_AddRefs(binaryStream));
    4004           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4005             : 
    4006             :   uint64_t timestamp;
    4007           0 :   rv = binaryStream->Read64(&timestamp);
    4008           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4009             : 
    4010             :   bool persisted;
    4011           0 :   rv = binaryStream->ReadBoolean(&persisted);
    4012           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4013           0 :     return rv;
    4014             :   }
    4015             : 
    4016             :   uint32_t reservedData1;
    4017           0 :   rv = binaryStream->Read32(&reservedData1);
    4018           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4019           0 :     return rv;
    4020             :   }
    4021             : 
    4022             :   uint32_t reservedData2;
    4023           0 :   rv = binaryStream->Read32(&reservedData2);
    4024           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4025           0 :     return rv;
    4026             :   }
    4027             : 
    4028           0 :   nsCString suffix;
    4029           0 :   rv = binaryStream->ReadCString(suffix);
    4030           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4031           0 :     return rv;
    4032             :   }
    4033             : 
    4034           0 :   nsCString group;
    4035           0 :   rv = binaryStream->ReadCString(group);
    4036           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4037             : 
    4038           0 :   nsCString origin;
    4039           0 :   rv = binaryStream->ReadCString(origin);
    4040           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4041             : 
    4042             :   // Currently unused (used to be isApp).
    4043             :   bool dummy;
    4044           0 :   rv = binaryStream->ReadBoolean(&dummy);
    4045           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4046           0 :     return rv;
    4047             :   }
    4048             : 
    4049           0 :   *aTimestamp = timestamp;
    4050           0 :   *aPersisted = persisted;
    4051           0 :   aSuffix = suffix;
    4052           0 :   aGroup = group;
    4053           0 :   aOrigin = origin;
    4054           0 :   return NS_OK;
    4055             : }
    4056             : 
    4057             : nsresult
    4058           0 : QuotaManager::GetDirectoryMetadata2WithRestore(nsIFile* aDirectory,
    4059             :                                                bool aPersistent,
    4060             :                                                int64_t* aTimestamp,
    4061             :                                                bool* aPersisted,
    4062             :                                                nsACString& aSuffix,
    4063             :                                                nsACString& aGroup,
    4064             :                                                nsACString& aOrigin)
    4065             : {
    4066             :   nsresult rv = GetDirectoryMetadata2(aDirectory,
    4067             :                                       aTimestamp,
    4068             :                                       aPersisted,
    4069             :                                       aSuffix,
    4070             :                                       aGroup,
    4071           0 :                                       aOrigin);
    4072           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4073           0 :     rv = RestoreDirectoryMetadata2(aDirectory, aPersistent);
    4074           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4075           0 :       return rv;
    4076             :     }
    4077             : 
    4078             :     rv = GetDirectoryMetadata2(aDirectory,
    4079             :                                aTimestamp,
    4080             :                                aPersisted,
    4081             :                                aSuffix,
    4082             :                                aGroup,
    4083           0 :                                aOrigin);
    4084           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4085           0 :       return rv;
    4086             :     }
    4087             :   }
    4088             : 
    4089           0 :   return NS_OK;
    4090             : }
    4091             : 
    4092             : nsresult
    4093           0 : QuotaManager::GetDirectoryMetadata2(nsIFile* aDirectory,
    4094             :                                     int64_t* aTimestamp,
    4095             :                                     bool* aPersisted)
    4096             : {
    4097           0 :   AssertIsOnIOThread();
    4098           0 :   MOZ_ASSERT(aDirectory);
    4099           0 :   MOZ_ASSERT(aTimestamp || aPersisted);
    4100           0 :   MOZ_ASSERT(mStorageInitialized);
    4101             : 
    4102           0 :   nsCOMPtr<nsIBinaryInputStream> binaryStream;
    4103           0 :   nsresult rv = GetBinaryInputStream(aDirectory,
    4104           0 :                                      NS_LITERAL_STRING(METADATA_V2_FILE_NAME),
    4105           0 :                                      getter_AddRefs(binaryStream));
    4106           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4107           0 :     return rv;
    4108             :   }
    4109             : 
    4110             :   uint64_t timestamp;
    4111           0 :   rv = binaryStream->Read64(&timestamp);
    4112           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4113           0 :     return rv;
    4114             :   }
    4115             : 
    4116             :   bool persisted;
    4117           0 :   if (aPersisted) {
    4118           0 :     rv = binaryStream->ReadBoolean(&persisted);
    4119           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4120           0 :       return rv;
    4121             :     }
    4122             :   }
    4123             : 
    4124           0 :   if (aTimestamp) {
    4125           0 :     *aTimestamp = timestamp;
    4126             :   }
    4127           0 :   if (aPersisted) {
    4128           0 :     *aPersisted = persisted;
    4129             :   }
    4130           0 :   return NS_OK;
    4131             : }
    4132             : 
    4133             : nsresult
    4134           0 : QuotaManager::GetDirectoryMetadata2WithRestore(nsIFile* aDirectory,
    4135             :                                                bool aPersistent,
    4136             :                                                int64_t* aTimestamp,
    4137             :                                                bool* aPersisted)
    4138             : {
    4139           0 :   nsresult rv = GetDirectoryMetadata2(aDirectory, aTimestamp, aPersisted);
    4140           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4141           0 :     rv = RestoreDirectoryMetadata2(aDirectory, aPersistent);
    4142           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4143           0 :       return rv;
    4144             :     }
    4145             : 
    4146           0 :     rv = GetDirectoryMetadata2(aDirectory, aTimestamp, aPersisted);
    4147           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4148           0 :       return rv;
    4149             :     }
    4150             :   }
    4151             : 
    4152           0 :   return NS_OK;
    4153             : }
    4154             : 
    4155             : nsresult
    4156           0 : QuotaManager::InitializeRepository(PersistenceType aPersistenceType)
    4157             : {
    4158           0 :   MOZ_ASSERT(aPersistenceType == PERSISTENCE_TYPE_TEMPORARY ||
    4159             :              aPersistenceType == PERSISTENCE_TYPE_DEFAULT);
    4160             : 
    4161             :   nsresult rv;
    4162             : 
    4163             :   nsCOMPtr<nsIFile> directory =
    4164           0 :     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    4165           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4166           0 :     return rv;
    4167             :   }
    4168             : 
    4169           0 :   rv = directory->InitWithPath(GetStoragePath(aPersistenceType));
    4170           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4171           0 :     return rv;
    4172             :   }
    4173             : 
    4174             :   bool created;
    4175           0 :   rv = EnsureDirectory(directory, &created);
    4176           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4177           0 :     return rv;
    4178             :   }
    4179             : 
    4180           0 :   nsCOMPtr<nsISimpleEnumerator> entries;
    4181           0 :   rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
    4182           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4183           0 :     return rv;
    4184             :   }
    4185             : 
    4186             :   bool hasMore;
    4187           0 :   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
    4188           0 :     nsCOMPtr<nsISupports> entry;
    4189           0 :     rv = entries->GetNext(getter_AddRefs(entry));
    4190           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4191           0 :       return rv;
    4192             :     }
    4193             : 
    4194           0 :     nsCOMPtr<nsIFile> childDirectory = do_QueryInterface(entry);
    4195           0 :     MOZ_ASSERT(childDirectory);
    4196             : 
    4197             :     bool isDirectory;
    4198           0 :     rv = childDirectory->IsDirectory(&isDirectory);
    4199           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4200           0 :       return rv;
    4201             :     }
    4202             : 
    4203           0 :     if (!isDirectory) {
    4204           0 :       nsString leafName;
    4205           0 :       rv = childDirectory->GetLeafName(leafName);
    4206           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4207           0 :         return rv;
    4208             :       }
    4209             : 
    4210           0 :       if (IsOSMetadata(leafName)) {
    4211           0 :         continue;
    4212             :       }
    4213             : 
    4214           0 :       UNKNOWN_FILE_WARNING(leafName);
    4215           0 :       return NS_ERROR_UNEXPECTED;
    4216             :     }
    4217             : 
    4218             :     int64_t timestamp;
    4219             :     bool persisted;
    4220           0 :     nsCString suffix;
    4221           0 :     nsCString group;
    4222           0 :     nsCString origin;
    4223           0 :     rv = GetDirectoryMetadata2WithRestore(childDirectory,
    4224             :                                           /* aPersistent */ false,
    4225             :                                           &timestamp,
    4226             :                                           &persisted,
    4227             :                                           suffix,
    4228             :                                           group,
    4229             :                                           origin);
    4230           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4231           0 :       return rv;
    4232             :     }
    4233             : 
    4234           0 :     rv = InitializeOrigin(aPersistenceType, group, origin, timestamp, persisted,
    4235             :                           childDirectory);
    4236           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4237           0 :       return rv;
    4238             :     }
    4239             :   }
    4240           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4241           0 :     return rv;
    4242             :   }
    4243             : 
    4244           0 :   return NS_OK;
    4245             : }
    4246             : 
    4247             : nsresult
    4248           0 : QuotaManager::InitializeOrigin(PersistenceType aPersistenceType,
    4249             :                                const nsACString& aGroup,
    4250             :                                const nsACString& aOrigin,
    4251             :                                int64_t aAccessTime,
    4252             :                                bool aPersisted,
    4253             :                                nsIFile* aDirectory)
    4254             : {
    4255           0 :   AssertIsOnIOThread();
    4256             : 
    4257             :   nsresult rv;
    4258             : 
    4259           0 :   bool trackQuota = aPersistenceType != PERSISTENCE_TYPE_PERSISTENT;
    4260             : 
    4261             :   // We need to initialize directories of all clients if they exists and also
    4262             :   // get the total usage to initialize the quota.
    4263           0 :   nsAutoPtr<UsageInfo> usageInfo;
    4264           0 :   if (trackQuota) {
    4265           0 :     usageInfo = new UsageInfo();
    4266             :   }
    4267             : 
    4268           0 :   nsCOMPtr<nsISimpleEnumerator> entries;
    4269           0 :   rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
    4270           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4271             : 
    4272             :   bool hasMore;
    4273           0 :   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
    4274           0 :     nsCOMPtr<nsISupports> entry;
    4275           0 :     rv = entries->GetNext(getter_AddRefs(entry));
    4276           0 :     NS_ENSURE_SUCCESS(rv, rv);
    4277             : 
    4278           0 :     nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
    4279           0 :     NS_ENSURE_TRUE(file, NS_NOINTERFACE);
    4280             : 
    4281             :     bool isDirectory;
    4282           0 :     rv = file->IsDirectory(&isDirectory);
    4283           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4284           0 :       return rv;
    4285             :     }
    4286             : 
    4287           0 :     nsString leafName;
    4288           0 :     rv = file->GetLeafName(leafName);
    4289           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4290           0 :       return rv;
    4291             :     }
    4292             : 
    4293           0 :     if (!isDirectory) {
    4294           0 :       if (IsOriginMetadata(leafName)) {
    4295           0 :         continue;
    4296             :       }
    4297             : 
    4298           0 :       if (IsTempMetadata(leafName)) {
    4299           0 :         rv = file->Remove(/* recursive */ false);
    4300           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    4301           0 :           return rv;
    4302             :         }
    4303             : 
    4304           0 :         continue;
    4305             :       }
    4306             : 
    4307           0 :       UNKNOWN_FILE_WARNING(leafName);
    4308           0 :       return NS_ERROR_UNEXPECTED;
    4309             :     }
    4310             : 
    4311             :     Client::Type clientType;
    4312           0 :     rv = Client::TypeFromText(leafName, clientType);
    4313           0 :     if (NS_FAILED(rv)) {
    4314           0 :       UNKNOWN_FILE_WARNING(leafName);
    4315           0 :       return NS_ERROR_UNEXPECTED;
    4316             :     }
    4317             : 
    4318           0 :     Atomic<bool> dummy(false);
    4319           0 :     rv = mClients[clientType]->InitOrigin(aPersistenceType,
    4320             :                                           aGroup,
    4321             :                                           aOrigin,
    4322             :                                           /* aCanceled */ dummy,
    4323           0 :                                           usageInfo);
    4324           0 :     NS_ENSURE_SUCCESS(rv, rv);
    4325             :   }
    4326             : 
    4327           0 :   if (trackQuota) {
    4328           0 :     InitQuotaForOrigin(aPersistenceType, aGroup, aOrigin,
    4329           0 :                        usageInfo->TotalUsage(), aAccessTime, aPersisted);
    4330             :   }
    4331             : 
    4332           0 :   return NS_OK;
    4333             : }
    4334             : 
    4335             : nsresult
    4336           0 : QuotaManager::MaybeUpgradeIndexedDBDirectory()
    4337             : {
    4338           0 :   AssertIsOnIOThread();
    4339             : 
    4340             :   nsresult rv;
    4341             : 
    4342             :   nsCOMPtr<nsIFile> indexedDBDir =
    4343           0 :     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    4344           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4345             : 
    4346           0 :   rv = indexedDBDir->InitWithPath(mIndexedDBPath);
    4347           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4348             : 
    4349             :   bool exists;
    4350           0 :   rv = indexedDBDir->Exists(&exists);
    4351           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4352             : 
    4353           0 :   if (!exists) {
    4354             :     // Nothing to upgrade.
    4355           0 :     return NS_OK;
    4356             :   }
    4357             : 
    4358             :   bool isDirectory;
    4359           0 :   rv = indexedDBDir->IsDirectory(&isDirectory);
    4360           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4361             : 
    4362           0 :   if (!isDirectory) {
    4363           0 :     NS_WARNING("indexedDB entry is not a directory!");
    4364           0 :     return NS_OK;
    4365             :   }
    4366             : 
    4367             :   nsCOMPtr<nsIFile> persistentStorageDir =
    4368           0 :     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    4369           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4370             : 
    4371           0 :   rv = persistentStorageDir->InitWithPath(mStoragePath);
    4372           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4373             : 
    4374           0 :   rv = persistentStorageDir->Append(NS_LITERAL_STRING(PERSISTENT_DIRECTORY_NAME));
    4375           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4376             : 
    4377           0 :   rv = persistentStorageDir->Exists(&exists);
    4378           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4379             : 
    4380           0 :   if (exists) {
    4381           0 :     NS_WARNING("indexedDB directory shouldn't exist after the upgrade!");
    4382           0 :     return NS_OK;
    4383             :   }
    4384             : 
    4385           0 :   nsCOMPtr<nsIFile> storageDir;
    4386           0 :   rv = persistentStorageDir->GetParent(getter_AddRefs(storageDir));
    4387           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4388             : 
    4389             :   // MoveTo() is atomic if the move happens on the same volume which should
    4390             :   // be our case, so even if we crash in the middle of the operation nothing
    4391             :   // breaks next time we try to initialize.
    4392             :   // However there's a theoretical possibility that the indexedDB directory
    4393             :   // is on different volume, but it should be rare enough that we don't have
    4394             :   // to worry about it.
    4395           0 :   rv = indexedDBDir->MoveTo(storageDir, NS_LITERAL_STRING(PERSISTENT_DIRECTORY_NAME));
    4396           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4397             : 
    4398           0 :   return NS_OK;
    4399             : }
    4400             : 
    4401             : nsresult
    4402           0 : QuotaManager::MaybeUpgradePersistentStorageDirectory()
    4403             : {
    4404           0 :   AssertIsOnIOThread();
    4405             : 
    4406             :   nsresult rv;
    4407             : 
    4408             :   nsCOMPtr<nsIFile> persistentStorageDir =
    4409           0 :     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    4410           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4411           0 :     return rv;
    4412             :   }
    4413             : 
    4414           0 :   rv = persistentStorageDir->InitWithPath(mStoragePath);
    4415           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4416           0 :     return rv;
    4417             :   }
    4418             : 
    4419           0 :   rv = persistentStorageDir->Append(NS_LITERAL_STRING(PERSISTENT_DIRECTORY_NAME));
    4420           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4421           0 :     return rv;
    4422             :   }
    4423             : 
    4424             :   bool exists;
    4425           0 :   rv = persistentStorageDir->Exists(&exists);
    4426           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4427           0 :     return rv;
    4428             :   }
    4429             : 
    4430           0 :   if (!exists) {
    4431             :     // Nothing to upgrade.
    4432           0 :     return NS_OK;
    4433             :   }
    4434             : 
    4435             :   bool isDirectory;
    4436           0 :   rv = persistentStorageDir->IsDirectory(&isDirectory);
    4437           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4438           0 :     return rv;
    4439             :   }
    4440             : 
    4441           0 :   if (!isDirectory) {
    4442           0 :     NS_WARNING("persistent entry is not a directory!");
    4443           0 :     return NS_OK;
    4444             :   }
    4445             : 
    4446             :   nsCOMPtr<nsIFile> defaultStorageDir =
    4447           0 :     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    4448           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4449           0 :     return rv;
    4450             :   }
    4451             : 
    4452           0 :   rv = defaultStorageDir->InitWithPath(mDefaultStoragePath);
    4453           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4454           0 :     return rv;
    4455             :   }
    4456             : 
    4457           0 :   rv = defaultStorageDir->Exists(&exists);
    4458           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4459           0 :     return rv;
    4460             :   }
    4461             : 
    4462           0 :   if (exists) {
    4463           0 :     NS_WARNING("storage/persistent shouldn't exist after the upgrade!");
    4464           0 :     return NS_OK;
    4465             :   }
    4466             : 
    4467             :   // Create real metadata files for origin directories in persistent storage.
    4468             :   RefPtr<CreateOrUpgradeDirectoryMetadataHelper> helper =
    4469             :     new CreateOrUpgradeDirectoryMetadataHelper(persistentStorageDir,
    4470           0 :                                                /* aPersistent */ true);
    4471             : 
    4472           0 :   rv = helper->CreateOrUpgradeMetadataFiles();
    4473           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4474           0 :     return rv;
    4475             :   }
    4476             : 
    4477             :   // Upgrade metadata files for origin directories in temporary storage.
    4478             :   nsCOMPtr<nsIFile> temporaryStorageDir =
    4479           0 :     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    4480           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4481           0 :     return rv;
    4482             :   }
    4483             : 
    4484           0 :   rv = temporaryStorageDir->InitWithPath(mTemporaryStoragePath);
    4485           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4486           0 :     return rv;
    4487             :   }
    4488             : 
    4489           0 :   rv = temporaryStorageDir->Exists(&exists);
    4490           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4491           0 :     return rv;
    4492             :   }
    4493             : 
    4494           0 :   if (exists) {
    4495           0 :     rv = temporaryStorageDir->IsDirectory(&isDirectory);
    4496           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4497           0 :       return rv;
    4498             :     }
    4499             : 
    4500           0 :     if (!isDirectory) {
    4501           0 :       NS_WARNING("temporary entry is not a directory!");
    4502           0 :       return NS_OK;
    4503             :     }
    4504             : 
    4505             :     helper =
    4506             :       new CreateOrUpgradeDirectoryMetadataHelper(temporaryStorageDir,
    4507           0 :                                                  /* aPersistent */ false);
    4508             : 
    4509           0 :     rv = helper->CreateOrUpgradeMetadataFiles();
    4510           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4511           0 :       return rv;
    4512             :     }
    4513             :   }
    4514             : 
    4515             :   // And finally rename persistent to default.
    4516           0 :   rv = persistentStorageDir->RenameTo(nullptr, NS_LITERAL_STRING(DEFAULT_DIRECTORY_NAME));
    4517           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4518           0 :     return rv;
    4519             :   }
    4520             : 
    4521           0 :   return NS_OK;
    4522             : }
    4523             : 
    4524             : nsresult
    4525           0 : QuotaManager::MaybeRemoveOldDirectories()
    4526             : {
    4527           0 :   AssertIsOnIOThread();
    4528             : 
    4529             :   nsresult rv;
    4530             : 
    4531             :   nsCOMPtr<nsIFile> indexedDBDir =
    4532           0 :     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    4533           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4534           0 :     return rv;
    4535             :   }
    4536             : 
    4537           0 :   rv = indexedDBDir->InitWithPath(mIndexedDBPath);
    4538           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4539           0 :     return rv;
    4540             :   }
    4541             : 
    4542             :   bool exists;
    4543           0 :   rv = indexedDBDir->Exists(&exists);
    4544           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4545           0 :     return rv;
    4546             :   }
    4547             : 
    4548           0 :   if (exists) {
    4549           0 :     QM_WARNING("Deleting old <profile>/indexedDB directory!");
    4550             : 
    4551           0 :     rv = indexedDBDir->Remove(/* aRecursive */ true);
    4552           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4553           0 :       return rv;
    4554             :     }
    4555             :   }
    4556             : 
    4557             :   nsCOMPtr<nsIFile> persistentStorageDir =
    4558           0 :     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    4559           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4560           0 :     return rv;
    4561             :   }
    4562             : 
    4563           0 :   rv = persistentStorageDir->InitWithPath(mStoragePath);
    4564           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4565           0 :     return rv;
    4566             :   }
    4567             : 
    4568           0 :   rv = persistentStorageDir->Append(NS_LITERAL_STRING(PERSISTENT_DIRECTORY_NAME));
    4569           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4570           0 :     return rv;
    4571             :   }
    4572             : 
    4573           0 :   rv = persistentStorageDir->Exists(&exists);
    4574           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4575           0 :     return rv;
    4576             :   }
    4577             : 
    4578           0 :   if (exists) {
    4579           0 :     QM_WARNING("Deleting old <profile>/storage/persistent directory!");
    4580             : 
    4581           0 :     rv = persistentStorageDir->Remove(/* aRecursive */ true);
    4582           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4583           0 :       return rv;
    4584             :     }
    4585             :   }
    4586             : 
    4587           0 :   return NS_OK;
    4588             : }
    4589             : 
    4590             : nsresult
    4591           0 : QuotaManager::UpgradeStorageFrom0_0To1_0(mozIStorageConnection* aConnection)
    4592             : {
    4593           0 :   AssertIsOnIOThread();
    4594           0 :   MOZ_ASSERT(aConnection);
    4595             : 
    4596           0 :   nsresult rv = MaybeUpgradeIndexedDBDirectory();
    4597           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4598           0 :     return rv;
    4599             :   }
    4600             : 
    4601           0 :   rv = MaybeUpgradePersistentStorageDirectory();
    4602           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4603           0 :     return rv;
    4604             :   }
    4605             : 
    4606           0 :   rv = MaybeRemoveOldDirectories();
    4607           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4608           0 :     return rv;
    4609             :   }
    4610             : 
    4611           0 :   for (const PersistenceType persistenceType : kAllPersistenceTypes) {
    4612             :     nsCOMPtr<nsIFile> directory =
    4613           0 :       do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    4614           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4615           0 :       return rv;
    4616             :     }
    4617             : 
    4618           0 :     rv = directory->InitWithPath(GetStoragePath(persistenceType));
    4619           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4620           0 :       return rv;
    4621             :     }
    4622             : 
    4623           0 :     bool persistent = persistenceType == PERSISTENCE_TYPE_PERSISTENT;
    4624             :     RefPtr<UpgradeStorageFrom0_0To1_0Helper> helper =
    4625           0 :       new UpgradeStorageFrom0_0To1_0Helper(directory, persistent);
    4626             : 
    4627           0 :     rv = helper->DoUpgrade();
    4628           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4629           0 :       return rv;
    4630             :     }
    4631             :   }
    4632             : 
    4633             : #ifdef DEBUG
    4634             :   {
    4635             :     int32_t storageVersion;
    4636           0 :     rv = aConnection->GetSchemaVersion(&storageVersion);
    4637           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4638           0 :       return rv;
    4639             :     }
    4640             : 
    4641           0 :     MOZ_ASSERT(storageVersion == 0);
    4642             :   }
    4643             : #endif
    4644             : 
    4645           0 :   rv = aConnection->SetSchemaVersion(MakeStorageVersion(1, 0));
    4646           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4647           0 :     return rv;
    4648             :   }
    4649             : 
    4650           0 :   return NS_OK;
    4651             : }
    4652             : 
    4653             : nsresult
    4654           0 : QuotaManager::UpgradeStorageFrom1_0To2_0(mozIStorageConnection* aConnection)
    4655             : {
    4656           0 :   AssertIsOnIOThread();
    4657           0 :   MOZ_ASSERT(aConnection);
    4658             : 
    4659             :   // The upgrade consists of a number of logically distinct bugs that
    4660             :   // intentionally got fixed at the same time to trigger just one major
    4661             :   // version bump.
    4662             :   //
    4663             :   //
    4664             :   // Morgue directory cleanup
    4665             :   // [Feature/Bug]:
    4666             :   // The original bug that added "on demand" morgue cleanup is 1165119.
    4667             :   //
    4668             :   // [Mutations]:
    4669             :   // Morgue directories are removed from all origin directories during the
    4670             :   // upgrade process. Origin initialization and usage calculation doesn't try
    4671             :   // to remove morgue directories anymore.
    4672             :   //
    4673             :   // [Downgrade-incompatible changes]:
    4674             :   // Morgue directories can reappear if user runs an already upgraded profile
    4675             :   // in an older version of Firefox. Morgue directories then prevent current
    4676             :   // Firefox from initializing and using the storage.
    4677             :   //
    4678             :   //
    4679             :   // App data removal
    4680             :   // [Feature/Bug]:
    4681             :   // The bug that removes isApp flags is 1311057.
    4682             :   //
    4683             :   // [Mutations]:
    4684             :   // Origin directories with appIds are removed during the upgrade process.
    4685             :   //
    4686             :   // [Downgrade-incompatible changes]:
    4687             :   // Origin directories with appIds can reappear if user runs an already
    4688             :   // upgraded profile in an older version of Firefox. Origin directories with
    4689             :   // appIds don't prevent current Firefox from initializing and using the
    4690             :   // storage, but they wouldn't ever be removed again, potentially causing
    4691             :   // problems once appId is removed from origin attributes.
    4692             :   //
    4693             :   //
    4694             :   // Strip obsolete origin attributes
    4695             :   // [Feature/Bug]:
    4696             :   // The bug that strips obsolete origin attributes is 1314361.
    4697             :   //
    4698             :   // [Mutations]:
    4699             :   // Origin directories with obsolete origin attributes are renamed and their
    4700             :   // metadata files are updated during the upgrade process.
    4701             :   //
    4702             :   // [Downgrade-incompatible changes]:
    4703             :   // Origin directories with obsolete origin attributes can reappear if user
    4704             :   // runs an already upgraded profile in an older version of Firefox. Origin
    4705             :   // directories with obsolete origin attributes don't prevent current Firefox
    4706             :   // from initializing and using the storage, but they wouldn't ever be upgraded
    4707             :   // again, potentially causing problems in future.
    4708             :   //
    4709             :   //
    4710             :   // File manager directory renaming (client specific)
    4711             :   // [Feature/Bug]:
    4712             :   // The original bug that added "on demand" file manager directory renaming is
    4713             :   // 1056939.
    4714             :   //
    4715             :   // [Mutations]:
    4716             :   // All file manager directories are renamed to contain the ".files" suffix.
    4717             :   //
    4718             :   // [Downgrade-incompatible changes]:
    4719             :   // File manager directories with the ".files" suffix prevent older versions of
    4720             :   // Firefox from initializing and using the storage.
    4721             :   // File manager directories without the ".files" suffix can appear if user
    4722             :   // runs an already upgraded profile in an older version of Firefox. File
    4723             :   // manager directories without the ".files" suffix then prevent current
    4724             :   // Firefox from initializing and using the storage.
    4725             : 
    4726             :   nsresult rv;
    4727             : 
    4728           0 :   for (const PersistenceType persistenceType : kAllPersistenceTypes) {
    4729             :     nsCOMPtr<nsIFile> directory =
    4730           0 :       do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    4731           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4732           0 :       return rv;
    4733             :     }
    4734             : 
    4735           0 :     rv = directory->InitWithPath(GetStoragePath(persistenceType));
    4736           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4737           0 :       return rv;
    4738             :     }
    4739             : 
    4740             :     bool exists;
    4741           0 :     rv = directory->Exists(&exists);
    4742           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4743           0 :       return rv;
    4744             :     }
    4745             : 
    4746           0 :     if (!exists) {
    4747           0 :       continue;
    4748             :     }
    4749             : 
    4750           0 :     bool persistent = persistenceType == PERSISTENCE_TYPE_PERSISTENT;
    4751             :     RefPtr<UpgradeStorageFrom1_0To2_0Helper> helper =
    4752           0 :       new UpgradeStorageFrom1_0To2_0Helper(directory, persistent);
    4753             : 
    4754           0 :     rv = helper->DoUpgrade();
    4755           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4756           0 :       return rv;
    4757             :     }
    4758             :   }
    4759             : 
    4760             : #ifdef DEBUG
    4761             :   {
    4762             :     int32_t storageVersion;
    4763           0 :     rv = aConnection->GetSchemaVersion(&storageVersion);
    4764           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4765           0 :       return rv;
    4766             :     }
    4767             : 
    4768           0 :     MOZ_ASSERT(storageVersion == MakeStorageVersion(1, 0));
    4769             :   }
    4770             : #endif
    4771             : 
    4772           0 :   rv = aConnection->SetSchemaVersion(MakeStorageVersion(2, 0));
    4773           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4774           0 :     return rv;
    4775             :   }
    4776             : 
    4777           0 :   return NS_OK;
    4778             : }
    4779             : 
    4780             : #ifdef DEBUG
    4781             : 
    4782             : void
    4783           0 : QuotaManager::AssertStorageIsInitialized() const
    4784             : {
    4785           0 :   AssertIsOnIOThread();
    4786           0 :   MOZ_ASSERT(mStorageInitialized);
    4787           0 : }
    4788             : 
    4789             : #endif // DEBUG
    4790             : 
    4791             : nsresult
    4792           0 : QuotaManager::EnsureStorageIsInitialized()
    4793             : {
    4794           0 :   AssertIsOnIOThread();
    4795             : 
    4796           0 :   if (mStorageInitialized) {
    4797           0 :     return NS_OK;
    4798             :   }
    4799             : 
    4800             :   nsresult rv;
    4801             : 
    4802             :   nsCOMPtr<nsIFile> storageFile =
    4803           0 :     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    4804           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4805           0 :     return rv;
    4806             :   }
    4807             : 
    4808           0 :   rv = storageFile->InitWithPath(mBasePath);
    4809           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4810           0 :     return rv;
    4811             :   }
    4812             : 
    4813           0 :   rv = storageFile->Append(NS_LITERAL_STRING(STORAGE_FILE_NAME));
    4814           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4815           0 :     return rv;
    4816             :   }
    4817             : 
    4818             :   nsCOMPtr<mozIStorageService> ss =
    4819           0 :     do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
    4820           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4821           0 :     return rv;
    4822             :   }
    4823             : 
    4824           0 :   nsCOMPtr<mozIStorageConnection> connection;
    4825           0 :   rv = ss->OpenUnsharedDatabase(storageFile, getter_AddRefs(connection));
    4826           0 :   if (rv == NS_ERROR_FILE_CORRUPTED) {
    4827             :     // Nuke the database file.
    4828           0 :     rv = storageFile->Remove(false);
    4829           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4830           0 :       return rv;
    4831             :     }
    4832             : 
    4833           0 :     rv = ss->OpenUnsharedDatabase(storageFile, getter_AddRefs(connection));
    4834             :   }
    4835             : 
    4836           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4837           0 :     return rv;
    4838             :   }
    4839             : 
    4840             :   // We want extra durability for this important file.
    4841           0 :   rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    4842             :     "PRAGMA synchronous = EXTRA;"
    4843           0 :   ));
    4844           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4845           0 :     return rv;
    4846             :   }
    4847             : 
    4848             :   // Check to make sure that the storage version is correct.
    4849             :   int32_t storageVersion;
    4850           0 :   rv = connection->GetSchemaVersion(&storageVersion);
    4851           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4852           0 :     return rv;
    4853             :   }
    4854             : 
    4855           0 :   if (GetMajorStorageVersion(storageVersion) > kMajorStorageVersion) {
    4856           0 :     NS_WARNING("Unable to initialize storage, version is too high!");
    4857           0 :     return NS_ERROR_FAILURE;
    4858             :   }
    4859             : 
    4860           0 :   if (storageVersion < kStorageVersion) {
    4861           0 :     const bool newDatabase = !storageVersion;
    4862             : 
    4863             :     nsCOMPtr<nsIFile> storageDir =
    4864           0 :       do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    4865           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4866           0 :       return rv;
    4867             :     }
    4868             : 
    4869           0 :     rv = storageDir->InitWithPath(mStoragePath);
    4870           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4871           0 :       return rv;
    4872             :     }
    4873             : 
    4874             :     bool exists;
    4875           0 :     rv = storageDir->Exists(&exists);
    4876           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4877           0 :       return rv;
    4878             :     }
    4879             : 
    4880           0 :     if (!exists) {
    4881             :       nsCOMPtr<nsIFile> indexedDBDir =
    4882           0 :         do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    4883           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4884           0 :         return rv;
    4885             :       }
    4886             : 
    4887           0 :       rv = indexedDBDir->InitWithPath(mIndexedDBPath);
    4888           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4889           0 :         return rv;
    4890             :       }
    4891             : 
    4892           0 :       rv = indexedDBDir->Exists(&exists);
    4893           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4894           0 :         return rv;
    4895             :       }
    4896             :     }
    4897             : 
    4898           0 :     const bool newDirectory = !exists;
    4899             : 
    4900           0 :     if (newDatabase) {
    4901             :       // Set the page size first.
    4902             :       if (kSQLitePageSizeOverride) {
    4903           0 :         rv = connection->ExecuteSimpleSQL(
    4904           0 :           nsPrintfCString("PRAGMA page_size = %" PRIu32 ";", kSQLitePageSizeOverride)
    4905           0 :         );
    4906           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    4907           0 :           return rv;
    4908             :         }
    4909             :       }
    4910             :     }
    4911             : 
    4912             :     mozStorageTransaction transaction(connection, false,
    4913           0 :                                   mozIStorageConnection::TRANSACTION_IMMEDIATE);
    4914             : 
    4915             :     // An upgrade method can upgrade the database, the storage or both.
    4916             :     // The upgrade loop below can only be avoided when there's no database and
    4917             :     // no storage yet (e.g. new profile).
    4918           0 :     if (newDatabase && newDirectory) {
    4919           0 :       rv = CreateTables(connection);
    4920           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4921           0 :         return rv;
    4922             :       }
    4923             : 
    4924           0 :       MOZ_ASSERT(NS_SUCCEEDED(connection->GetSchemaVersion(&storageVersion)));
    4925           0 :       MOZ_ASSERT(storageVersion == kStorageVersion);
    4926             :     } else {
    4927             :       // This logic needs to change next time we change the storage!
    4928             :       static_assert(kStorageVersion == int32_t((2 << 16) + 0),
    4929             :                     "Upgrade function needed due to storage version increase.");
    4930             : 
    4931           0 :       while (storageVersion != kStorageVersion) {
    4932           0 :         if (storageVersion == 0) {
    4933           0 :           rv = UpgradeStorageFrom0_0To1_0(connection);
    4934           0 :         } else if (storageVersion == MakeStorageVersion(1, 0)) {
    4935           0 :           rv = UpgradeStorageFrom1_0To2_0(connection);
    4936             :         } else {
    4937             :           NS_WARNING("Unable to initialize storage, no upgrade path is "
    4938           0 :                      "available!");
    4939           0 :           return NS_ERROR_FAILURE;
    4940             :         }
    4941             : 
    4942           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    4943           0 :           return rv;
    4944             :         }
    4945             : 
    4946           0 :         rv = connection->GetSchemaVersion(&storageVersion);
    4947           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    4948           0 :           return rv;
    4949             :         }
    4950             :       }
    4951             : 
    4952           0 :       MOZ_ASSERT(storageVersion == kStorageVersion);
    4953             :     }
    4954             : 
    4955           0 :     rv = transaction.Commit();
    4956           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4957           0 :       return rv;
    4958             :     }
    4959             :   }
    4960             : 
    4961           0 :   mStorageInitialized = true;
    4962             : 
    4963           0 :   return NS_OK;
    4964             : }
    4965             : 
    4966             : void
    4967           0 : QuotaManager::OpenDirectory(PersistenceType aPersistenceType,
    4968             :                             const nsACString& aGroup,
    4969             :                             const nsACString& aOrigin,
    4970             :                             Client::Type aClientType,
    4971             :                             bool aExclusive,
    4972             :                             OpenDirectoryListener* aOpenListener)
    4973             : {
    4974           0 :   AssertIsOnOwningThread();
    4975             : 
    4976             :   RefPtr<DirectoryLockImpl> lock =
    4977           0 :     CreateDirectoryLock(Nullable<PersistenceType>(aPersistenceType),
    4978             :                         aGroup,
    4979           0 :                         OriginScope::FromOrigin(aOrigin),
    4980           0 :                         Nullable<Client::Type>(aClientType),
    4981             :                         aExclusive,
    4982             :                         false,
    4983           0 :                         aOpenListener);
    4984           0 :   MOZ_ASSERT(lock);
    4985           0 : }
    4986             : 
    4987             : void
    4988           0 : QuotaManager::OpenDirectoryInternal(const Nullable<PersistenceType>& aPersistenceType,
    4989             :                                     const OriginScope& aOriginScope,
    4990             :                                     const Nullable<Client::Type>& aClientType,
    4991             :                                     bool aExclusive,
    4992             :                                     OpenDirectoryListener* aOpenListener)
    4993             : {
    4994           0 :   AssertIsOnOwningThread();
    4995             : 
    4996             :   RefPtr<DirectoryLockImpl> lock =
    4997           0 :     CreateDirectoryLock(aPersistenceType,
    4998           0 :                         EmptyCString(),
    4999             :                         aOriginScope,
    5000           0 :                         Nullable<Client::Type>(aClientType),
    5001             :                         aExclusive,
    5002             :                         true,
    5003           0 :                         aOpenListener);
    5004           0 :   MOZ_ASSERT(lock);
    5005             : 
    5006           0 :   if (!aExclusive) {
    5007           0 :     return;
    5008             :   }
    5009             : 
    5010             :   // All the locks that block this new exclusive lock need to be invalidated.
    5011             :   // We also need to notify clients to abort operations for them.
    5012             :   AutoTArray<nsAutoPtr<nsTHashtable<nsCStringHashKey>>,
    5013           0 :                Client::TYPE_MAX> origins;
    5014           0 :   origins.SetLength(Client::TYPE_MAX);
    5015             : 
    5016             :   const nsTArray<DirectoryLockImpl*>& blockedOnLocks =
    5017           0 :     lock->GetBlockedOnLocks();
    5018             : 
    5019           0 :   for (DirectoryLockImpl* blockedOnLock : blockedOnLocks) {
    5020           0 :     blockedOnLock->Invalidate();
    5021             : 
    5022           0 :     if (!blockedOnLock->IsInternal()) {
    5023           0 :       MOZ_ASSERT(!blockedOnLock->GetClientType().IsNull());
    5024           0 :       Client::Type clientType = blockedOnLock->GetClientType().Value();
    5025           0 :       MOZ_ASSERT(clientType < Client::TYPE_MAX);
    5026             : 
    5027           0 :       const OriginScope& originScope = blockedOnLock->GetOriginScope();
    5028           0 :       MOZ_ASSERT(originScope.IsOrigin());
    5029           0 :       MOZ_ASSERT(!originScope.GetOrigin().IsEmpty());
    5030             : 
    5031           0 :       nsAutoPtr<nsTHashtable<nsCStringHashKey>>& origin = origins[clientType];
    5032           0 :       if (!origin) {
    5033           0 :         origin = new nsTHashtable<nsCStringHashKey>();
    5034             :       }
    5035           0 :       origin->PutEntry(originScope.GetOrigin());
    5036             :     }
    5037             :   }
    5038             : 
    5039           0 :   for (uint32_t index : IntegerRange(uint32_t(Client::TYPE_MAX))) {
    5040           0 :     if (origins[index]) {
    5041           0 :       for (auto iter = origins[index]->Iter(); !iter.Done(); iter.Next()) {
    5042           0 :         MOZ_ASSERT(mClients[index]);
    5043             : 
    5044           0 :         mClients[index]->AbortOperations(iter.Get()->GetKey());
    5045             :       }
    5046             :     }
    5047             :   }
    5048             : }
    5049             : 
    5050             : nsresult
    5051           0 : QuotaManager::EnsureOriginIsInitialized(PersistenceType aPersistenceType,
    5052             :                                         const nsACString& aSuffix,
    5053             :                                         const nsACString& aGroup,
    5054             :                                         const nsACString& aOrigin,
    5055             :                                         nsIFile** aDirectory)
    5056             : {
    5057           0 :   AssertIsOnIOThread();
    5058           0 :   MOZ_ASSERT(aDirectory);
    5059             : 
    5060           0 :   nsCOMPtr<nsIFile> directory;
    5061             :   bool created;
    5062           0 :   nsresult rv = EnsureOriginIsInitializedInternal(aPersistenceType,
    5063             :                                                   aSuffix,
    5064             :                                                   aGroup,
    5065             :                                                   aOrigin,
    5066           0 :                                                   getter_AddRefs(directory),
    5067           0 :                                                   &created);
    5068           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    5069           0 :     return rv;
    5070             :   }
    5071             : 
    5072           0 :   directory.forget(aDirectory);
    5073           0 :   return NS_OK;
    5074             : }
    5075             : 
    5076             : nsresult
    5077           0 : QuotaManager::EnsureOriginIsInitializedInternal(
    5078             :                                                PersistenceType aPersistenceType,
    5079             :                                                const nsACString& aSuffix,
    5080             :                                                const nsACString& aGroup,
    5081             :                                                const nsACString& aOrigin,
    5082             :                                                nsIFile** aDirectory,
    5083             :                                                bool* aCreated)
    5084             : {
    5085           0 :   AssertIsOnIOThread();
    5086           0 :   MOZ_ASSERT(aDirectory);
    5087           0 :   MOZ_ASSERT(aCreated);
    5088             : 
    5089           0 :   nsresult rv = EnsureStorageIsInitialized();
    5090           0 :   NS_ENSURE_SUCCESS(rv, rv);
    5091             : 
    5092             :   // Get directory for this origin and persistence type.
    5093           0 :   nsCOMPtr<nsIFile> directory;
    5094           0 :   rv = GetDirectoryForOrigin(aPersistenceType, aOrigin,
    5095           0 :                              getter_AddRefs(directory));
    5096           0 :   NS_ENSURE_SUCCESS(rv, rv);
    5097             : 
    5098           0 :   if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
    5099           0 :     if (mInitializedOrigins.Contains(aOrigin)) {
    5100           0 :       directory.forget(aDirectory);
    5101           0 :       *aCreated = false;
    5102           0 :       return NS_OK;
    5103             :     }
    5104           0 :   } else if (!mTemporaryStorageInitialized) {
    5105           0 :     rv = InitializeRepository(aPersistenceType);
    5106           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    5107             :       // We have to cleanup partially initialized quota.
    5108           0 :       RemoveQuota();
    5109             : 
    5110           0 :       return rv;
    5111             :     }
    5112             : 
    5113           0 :     rv = InitializeRepository(ComplementaryPersistenceType(aPersistenceType));
    5114           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    5115             :       // We have to cleanup partially initialized quota.
    5116           0 :       RemoveQuota();
    5117             : 
    5118           0 :       return rv;
    5119             :     }
    5120             : 
    5121           0 :     if (gFixedLimitKB >= 0) {
    5122           0 :       mTemporaryStorageLimit = static_cast<uint64_t>(gFixedLimitKB) * 1024;
    5123             :     }
    5124             :     else {
    5125             :       nsCOMPtr<nsIFile> storageDir =
    5126           0 :         do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    5127           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    5128           0 :         return rv;
    5129             :       }
    5130             : 
    5131           0 :       rv = storageDir->InitWithPath(GetStoragePath());
    5132           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    5133           0 :         return rv;
    5134             :       }
    5135             : 
    5136           0 :       rv = GetTemporaryStorageLimit(storageDir, mTemporaryStorageUsage,
    5137             :                                     &mTemporaryStorageLimit);
    5138           0 :       NS_ENSURE_SUCCESS(rv, rv);
    5139             :     }
    5140             : 
    5141           0 :     mTemporaryStorageInitialized = true;
    5142             : 
    5143           0 :     CheckTemporaryStorageLimits();
    5144             :   }
    5145             : 
    5146             :   bool created;
    5147           0 :   rv = EnsureOriginDirectory(directory, &created);
    5148           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    5149           0 :     return rv;
    5150             :   }
    5151             : 
    5152             :   int64_t timestamp;
    5153           0 :   if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
    5154           0 :     if (created) {
    5155           0 :       rv = CreateDirectoryMetadataFiles(directory,
    5156             :                                         /* aPersisted */ true,
    5157             :                                         aSuffix,
    5158             :                                         aGroup,
    5159             :                                         aOrigin,
    5160             :                                         &timestamp);
    5161           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    5162           0 :         return rv;
    5163             :       }
    5164             :     } else {
    5165           0 :       rv = GetDirectoryMetadata2WithRestore(directory,
    5166             :                                             /* aPersistent */ true,
    5167             :                                             &timestamp,
    5168             :                                             /* aPersisted */ nullptr);
    5169           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    5170           0 :         return rv;
    5171             :       }
    5172             : 
    5173           0 :       MOZ_ASSERT(timestamp <= PR_Now());
    5174             :     }
    5175             : 
    5176           0 :     rv = InitializeOrigin(aPersistenceType, aGroup, aOrigin, timestamp,
    5177             :                           /* aPersisted */ true, directory);
    5178           0 :     NS_ENSURE_SUCCESS(rv, rv);
    5179             : 
    5180           0 :     mInitializedOrigins.AppendElement(aOrigin);
    5181           0 :   } else if (created) {
    5182           0 :     rv = CreateDirectoryMetadataFiles(directory,
    5183             :                                       /* aPersisted */ false,
    5184             :                                       aSuffix,
    5185             :                                       aGroup,
    5186             :                                       aOrigin,
    5187             :                                       &timestamp);
    5188           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    5189           0 :       return rv;
    5190             :     }
    5191             : 
    5192             :     // Don't need to traverse the directory, since it's empty.
    5193             :     InitQuotaForOrigin(aPersistenceType,
    5194             :                        aGroup,
    5195             :                        aOrigin,
    5196             :                        /* aUsageBytes */ 0,
    5197             :                        timestamp,
    5198           0 :                        /* aPersisted */ false);
    5199             :   }
    5200             : 
    5201           0 :   directory.forget(aDirectory);
    5202           0 :   *aCreated = created;
    5203           0 :   return NS_OK;
    5204             : }
    5205             : 
    5206             : void
    5207           0 : QuotaManager::OriginClearCompleted(PersistenceType aPersistenceType,
    5208             :                                    const nsACString& aOrigin)
    5209             : {
    5210           0 :   AssertIsOnIOThread();
    5211             : 
    5212           0 :   if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
    5213           0 :     mInitializedOrigins.RemoveElement(aOrigin);
    5214             :   }
    5215             : 
    5216           0 :   for (uint32_t index = 0; index < Client::TYPE_MAX; index++) {
    5217           0 :     mClients[index]->OnOriginClearCompleted(aPersistenceType, aOrigin);
    5218             :   }
    5219           0 : }
    5220             : 
    5221             : void
    5222           0 : QuotaManager::ResetOrClearCompleted()
    5223             : {
    5224           0 :   AssertIsOnIOThread();
    5225             : 
    5226           0 :   mInitializedOrigins.Clear();
    5227           0 :   mTemporaryStorageInitialized = false;
    5228           0 :   mStorageInitialized = false;
    5229             : 
    5230           0 :   ReleaseIOThreadObjects();
    5231           0 : }
    5232             : 
    5233             : Client*
    5234           0 : QuotaManager::GetClient(Client::Type aClientType)
    5235             : {
    5236           0 :   MOZ_ASSERT(aClientType >= Client::IDB);
    5237           0 :   MOZ_ASSERT(aClientType < Client::TYPE_MAX);
    5238             : 
    5239           0 :   return mClients.ElementAt(aClientType);
    5240             : }
    5241             : 
    5242             : uint64_t
    5243           0 : QuotaManager::GetGroupLimit() const
    5244             : {
    5245           0 :   MOZ_ASSERT(mTemporaryStorageInitialized);
    5246             : 
    5247             :   // To avoid one group evicting all the rest, limit the amount any one group
    5248             :   // can use to 20%. To prevent individual sites from using exorbitant amounts
    5249             :   // of storage where there is a lot of free space, cap the group limit to 2GB.
    5250           0 :   uint64_t x = std::min<uint64_t>(mTemporaryStorageLimit * .20, 2 GB);
    5251             : 
    5252             :   // In low-storage situations, make an exception (while not exceeding the total
    5253             :   // storage limit).
    5254             :   return std::min<uint64_t>(mTemporaryStorageLimit,
    5255           0 :                             std::max<uint64_t>(x, 10 MB));
    5256             : }
    5257             : 
    5258             : void
    5259           0 : QuotaManager::GetGroupUsageAndLimit(const nsACString& aGroup,
    5260             :                                     UsageInfo* aUsageInfo)
    5261             : {
    5262           0 :   AssertIsOnIOThread();
    5263           0 :   MOZ_ASSERT(aUsageInfo);
    5264             : 
    5265             :   {
    5266           0 :     MutexAutoLock lock(mQuotaMutex);
    5267             : 
    5268           0 :     aUsageInfo->SetLimit(GetGroupLimit());
    5269           0 :     aUsageInfo->ResetUsage();
    5270             : 
    5271             :     GroupInfoPair* pair;
    5272           0 :     if (!mGroupInfoPairs.Get(aGroup, &pair)) {
    5273           0 :       return;
    5274             :     }
    5275             : 
    5276             :     // Calculate temporary group usage
    5277             :     RefPtr<GroupInfo> temporaryGroupInfo =
    5278           0 :       pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
    5279           0 :     if (temporaryGroupInfo) {
    5280           0 :       aUsageInfo->AppendToDatabaseUsage(temporaryGroupInfo->mUsage);
    5281             :     }
    5282             : 
    5283             :     // Calculate default group usage
    5284             :     RefPtr<GroupInfo> defaultGroupInfo =
    5285           0 :       pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
    5286           0 :     if (defaultGroupInfo) {
    5287           0 :       aUsageInfo->AppendToDatabaseUsage(defaultGroupInfo->mUsage);
    5288             :     }
    5289             :   }
    5290             : }
    5291             : 
    5292             : // static
    5293             : void
    5294           0 : QuotaManager::GetStorageId(PersistenceType aPersistenceType,
    5295             :                            const nsACString& aOrigin,
    5296             :                            Client::Type aClientType,
    5297             :                            nsACString& aDatabaseId)
    5298             : {
    5299           0 :   nsAutoCString str;
    5300           0 :   str.AppendInt(aPersistenceType);
    5301           0 :   str.Append('*');
    5302           0 :   str.Append(aOrigin);
    5303           0 :   str.Append('*');
    5304           0 :   str.AppendInt(aClientType);
    5305             : 
    5306           0 :   aDatabaseId = str;
    5307           0 : }
    5308             : 
    5309             : // static
    5310             : nsresult
    5311           0 : QuotaManager::GetInfoFromPrincipal(nsIPrincipal* aPrincipal,
    5312             :                                    nsACString* aSuffix,
    5313             :                                    nsACString* aGroup,
    5314             :                                    nsACString* aOrigin)
    5315             : {
    5316           0 :   MOZ_ASSERT(NS_IsMainThread());
    5317           0 :   MOZ_ASSERT(aPrincipal);
    5318             : 
    5319           0 :   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
    5320           0 :     GetInfoForChrome(aSuffix, aGroup, aOrigin);
    5321           0 :     return NS_OK;
    5322             :   }
    5323             : 
    5324             : 
    5325           0 :   if (aPrincipal->GetIsNullPrincipal()) {
    5326           0 :     NS_WARNING("IndexedDB not supported from this principal!");
    5327           0 :     return NS_ERROR_FAILURE;
    5328             :   }
    5329             : 
    5330           0 :   nsCString origin;
    5331           0 :   nsresult rv = aPrincipal->GetOrigin(origin);
    5332           0 :   NS_ENSURE_SUCCESS(rv, rv);
    5333             : 
    5334           0 :   if (origin.EqualsLiteral(kChromeOrigin)) {
    5335           0 :     NS_WARNING("Non-chrome principal can't use chrome origin!");
    5336           0 :     return NS_ERROR_FAILURE;
    5337             :   }
    5338             : 
    5339           0 :   nsCString suffix;
    5340           0 :   aPrincipal->OriginAttributesRef().CreateSuffix(suffix);
    5341             : 
    5342           0 :   if (aSuffix)
    5343             :   {
    5344           0 :     aSuffix->Assign(suffix);
    5345             :   }
    5346             : 
    5347           0 :   if (aGroup) {
    5348           0 :     nsCString baseDomain;
    5349           0 :     rv = aPrincipal->GetBaseDomain(baseDomain);
    5350           0 :     if (NS_FAILED(rv)) {
    5351             :       // A hack for JetPack.
    5352             : 
    5353           0 :       nsCOMPtr<nsIURI> uri;
    5354           0 :       rv = aPrincipal->GetURI(getter_AddRefs(uri));
    5355           0 :       NS_ENSURE_SUCCESS(rv, rv);
    5356             : 
    5357           0 :       bool isIndexedDBURI = false;
    5358           0 :       rv = uri->SchemeIs("indexedDB", &isIndexedDBURI);
    5359           0 :       NS_ENSURE_SUCCESS(rv, rv);
    5360             : 
    5361           0 :       if (isIndexedDBURI) {
    5362           0 :         rv = NS_OK;
    5363             :       }
    5364             :     }
    5365           0 :     NS_ENSURE_SUCCESS(rv, rv);
    5366             : 
    5367           0 :     if (baseDomain.IsEmpty()) {
    5368           0 :       aGroup->Assign(origin);
    5369             :     } else {
    5370           0 :       aGroup->Assign(baseDomain + suffix);
    5371             :     }
    5372             :   }
    5373             : 
    5374           0 :   if (aOrigin) {
    5375           0 :     aOrigin->Assign(origin);
    5376             :   }
    5377             : 
    5378           0 :   return NS_OK;
    5379             : }
    5380             : 
    5381             : // static
    5382             : nsresult
    5383           0 : QuotaManager::GetInfoFromWindow(nsPIDOMWindowOuter* aWindow,
    5384             :                                 nsACString* aSuffix,
    5385             :                                 nsACString* aGroup,
    5386             :                                 nsACString* aOrigin)
    5387             : {
    5388           0 :   MOZ_ASSERT(NS_IsMainThread());
    5389           0 :   MOZ_ASSERT(aWindow);
    5390             : 
    5391           0 :   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
    5392           0 :   NS_ENSURE_TRUE(sop, NS_ERROR_FAILURE);
    5393             : 
    5394           0 :   nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
    5395           0 :   NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
    5396             : 
    5397             :   nsresult rv =
    5398           0 :     GetInfoFromPrincipal(principal, aSuffix, aGroup, aOrigin);
    5399           0 :   NS_ENSURE_SUCCESS(rv, rv);
    5400             : 
    5401           0 :   return NS_OK;
    5402             : }
    5403             : 
    5404             : // static
    5405             : void
    5406           0 : QuotaManager::GetInfoForChrome(nsACString* aSuffix,
    5407             :                                nsACString* aGroup,
    5408             :                                nsACString* aOrigin)
    5409             : {
    5410           0 :   MOZ_ASSERT(NS_IsMainThread());
    5411           0 :   MOZ_ASSERT(nsContentUtils::LegacyIsCallerChromeOrNativeCode());
    5412             : 
    5413           0 :   if (aSuffix) {
    5414           0 :     aSuffix->Assign(EmptyCString());
    5415             :   }
    5416           0 :   if (aGroup) {
    5417           0 :     ChromeOrigin(*aGroup);
    5418             :   }
    5419           0 :   if (aOrigin) {
    5420           0 :     ChromeOrigin(*aOrigin);
    5421             :   }
    5422           0 : }
    5423             : 
    5424             : // static
    5425             : bool
    5426           0 : QuotaManager::IsOriginInternal(const nsACString& aOrigin)
    5427             : {
    5428             :   // The first prompt is not required for these origins.
    5429           0 :   if (aOrigin.EqualsLiteral(kChromeOrigin) ||
    5430           0 :       StringBeginsWith(aOrigin, nsDependentCString(kAboutHomeOriginPrefix)) ||
    5431           0 :       StringBeginsWith(aOrigin, nsDependentCString(kIndexedDBOriginPrefix)) ||
    5432           0 :       StringBeginsWith(aOrigin, nsDependentCString(kResourceOriginPrefix))) {
    5433           0 :     return true;
    5434             :   }
    5435             : 
    5436           0 :   return false;
    5437             : }
    5438             : 
    5439             : // static
    5440             : void
    5441           0 : QuotaManager::ChromeOrigin(nsACString& aOrigin)
    5442             : {
    5443           0 :   aOrigin.AssignLiteral(kChromeOrigin);
    5444           0 : }
    5445             : 
    5446             : // static
    5447             : bool
    5448           0 : QuotaManager::AreOriginsEqualOnDisk(nsACString& aOrigin1,
    5449             :                                     nsACString& aOrigin2)
    5450             : {
    5451           0 :   nsCString origin1Sanitized(aOrigin1);
    5452           0 :   SanitizeOriginString(origin1Sanitized);
    5453             : 
    5454           0 :   nsCString origin2Sanitized(aOrigin2);
    5455           0 :   SanitizeOriginString(origin2Sanitized);
    5456             : 
    5457           0 :   return origin1Sanitized == origin2Sanitized;
    5458             : }
    5459             : 
    5460             : uint64_t
    5461           0 : QuotaManager::LockedCollectOriginsForEviction(
    5462             :                                   uint64_t aMinSizeToBeFreed,
    5463             :                                   nsTArray<RefPtr<DirectoryLockImpl>>& aLocks)
    5464             : {
    5465           0 :   mQuotaMutex.AssertCurrentThreadOwns();
    5466             : 
    5467             :   RefPtr<CollectOriginsHelper> helper =
    5468           0 :     new CollectOriginsHelper(mQuotaMutex, aMinSizeToBeFreed);
    5469             : 
    5470             :   // Unlock while calling out to XPCOM (code behind the dispatch method needs
    5471             :   // to acquire its own lock which can potentially lead to a deadlock and it
    5472             :   // also calls an observer that can do various stuff like IO, so it's better
    5473             :   // to not hold our mutex while that happens).
    5474             :   {
    5475           0 :     MutexAutoUnlock autoUnlock(mQuotaMutex);
    5476             : 
    5477           0 :     MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(helper, NS_DISPATCH_NORMAL));
    5478             :   }
    5479             : 
    5480           0 :   return helper->BlockAndReturnOriginsForEviction(aLocks);
    5481             : }
    5482             : 
    5483             : void
    5484           0 : QuotaManager::LockedRemoveQuotaForOrigin(PersistenceType aPersistenceType,
    5485             :                                          const nsACString& aGroup,
    5486             :                                          const nsACString& aOrigin)
    5487             : {
    5488           0 :   mQuotaMutex.AssertCurrentThreadOwns();
    5489           0 :   MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
    5490             : 
    5491             :   GroupInfoPair* pair;
    5492           0 :   mGroupInfoPairs.Get(aGroup, &pair);
    5493             : 
    5494           0 :   if (!pair) {
    5495           0 :     return;
    5496             :   }
    5497             : 
    5498           0 :   RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
    5499           0 :   if (groupInfo) {
    5500           0 :     groupInfo->LockedRemoveOriginInfo(aOrigin);
    5501             : 
    5502           0 :     if (!groupInfo->LockedHasOriginInfos()) {
    5503           0 :       pair->LockedClearGroupInfo(aPersistenceType);
    5504             : 
    5505           0 :       if (!pair->LockedHasGroupInfos()) {
    5506           0 :         mGroupInfoPairs.Remove(aGroup);
    5507             :       }
    5508             :     }
    5509             :   }
    5510             : }
    5511             : 
    5512             : already_AddRefed<OriginInfo>
    5513           0 : QuotaManager::LockedGetOriginInfo(PersistenceType aPersistenceType,
    5514             :                                   const nsACString& aGroup,
    5515             :                                   const nsACString& aOrigin)
    5516             : {
    5517           0 :   mQuotaMutex.AssertCurrentThreadOwns();
    5518           0 :   MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
    5519             : 
    5520             :   GroupInfoPair* pair;
    5521           0 :   if (mGroupInfoPairs.Get(aGroup, &pair)) {
    5522           0 :     RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
    5523           0 :     if (groupInfo) {
    5524           0 :       return groupInfo->LockedGetOriginInfo(aOrigin);
    5525             :     }
    5526             :   }
    5527             : 
    5528           0 :   return nullptr;
    5529             : }
    5530             : 
    5531             : void
    5532           0 : QuotaManager::CheckTemporaryStorageLimits()
    5533             : {
    5534           0 :   AssertIsOnIOThread();
    5535             : 
    5536           0 :   nsTArray<OriginInfo*> doomedOriginInfos;
    5537             :   {
    5538           0 :     MutexAutoLock lock(mQuotaMutex);
    5539             : 
    5540           0 :     for (auto iter = mGroupInfoPairs.Iter(); !iter.Done(); iter.Next()) {
    5541           0 :       GroupInfoPair* pair = iter.UserData();
    5542             : 
    5543           0 :       MOZ_ASSERT(!iter.Key().IsEmpty(), "Empty key!");
    5544           0 :       MOZ_ASSERT(pair, "Null pointer!");
    5545             : 
    5546           0 :       uint64_t groupUsage = 0;
    5547             : 
    5548             :       RefPtr<GroupInfo> temporaryGroupInfo =
    5549           0 :         pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
    5550           0 :       if (temporaryGroupInfo) {
    5551           0 :         groupUsage += temporaryGroupInfo->mUsage;
    5552             :       }
    5553             : 
    5554             :       RefPtr<GroupInfo> defaultGroupInfo =
    5555           0 :         pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
    5556           0 :       if (defaultGroupInfo) {
    5557           0 :         groupUsage += defaultGroupInfo->mUsage;
    5558             :       }
    5559             : 
    5560           0 :       if (groupUsage > 0) {
    5561           0 :         QuotaManager* quotaManager = QuotaManager::Get();
    5562           0 :         MOZ_ASSERT(quotaManager, "Shouldn't be null!");
    5563             : 
    5564           0 :         if (groupUsage > quotaManager->GetGroupLimit()) {
    5565           0 :           nsTArray<OriginInfo*> originInfos;
    5566           0 :           if (temporaryGroupInfo) {
    5567           0 :             originInfos.AppendElements(temporaryGroupInfo->mOriginInfos);
    5568             :           }
    5569           0 :           if (defaultGroupInfo) {
    5570           0 :             originInfos.AppendElements(defaultGroupInfo->mOriginInfos);
    5571             :           }
    5572           0 :           originInfos.Sort(OriginInfoLRUComparator());
    5573             : 
    5574           0 :           for (uint32_t i = 0; i < originInfos.Length(); i++) {
    5575           0 :             OriginInfo* originInfo = originInfos[i];
    5576           0 :             if (originInfo->LockedPersisted()) {
    5577           0 :               continue;
    5578             :             }
    5579             : 
    5580           0 :             doomedOriginInfos.AppendElement(originInfo);
    5581           0 :             groupUsage -= originInfo->mUsage;
    5582             : 
    5583           0 :             if (groupUsage <= quotaManager->GetGroupLimit()) {
    5584           0 :               break;
    5585             :             }
    5586             :           }
    5587             :         }
    5588             :       }
    5589             :     }
    5590             : 
    5591           0 :     uint64_t usage = 0;
    5592           0 :     for (uint32_t index = 0; index < doomedOriginInfos.Length(); index++) {
    5593           0 :       usage += doomedOriginInfos[index]->mUsage;
    5594             :     }
    5595             : 
    5596           0 :     if (mTemporaryStorageUsage - usage > mTemporaryStorageLimit) {
    5597           0 :       nsTArray<OriginInfo*> originInfos;
    5598             : 
    5599           0 :       for (auto iter = mGroupInfoPairs.Iter(); !iter.Done(); iter.Next()) {
    5600           0 :         GroupInfoPair* pair = iter.UserData();
    5601             : 
    5602           0 :         MOZ_ASSERT(!iter.Key().IsEmpty(), "Empty key!");
    5603           0 :         MOZ_ASSERT(pair, "Null pointer!");
    5604             : 
    5605             :         RefPtr<GroupInfo> groupInfo =
    5606           0 :           pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
    5607           0 :         if (groupInfo) {
    5608           0 :           originInfos.AppendElements(groupInfo->mOriginInfos);
    5609             :         }
    5610             : 
    5611           0 :         groupInfo = pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
    5612           0 :         if (groupInfo) {
    5613           0 :           originInfos.AppendElements(groupInfo->mOriginInfos);
    5614             :         }
    5615             :       }
    5616             : 
    5617           0 :       for (uint32_t index = originInfos.Length(); index > 0; index--) {
    5618           0 :         if (doomedOriginInfos.Contains(originInfos[index - 1]) ||
    5619           0 :             originInfos[index - 1]->LockedPersisted()) {
    5620           0 :           originInfos.RemoveElementAt(index - 1);
    5621             :         }
    5622             :       }
    5623             : 
    5624           0 :       originInfos.Sort(OriginInfoLRUComparator());
    5625             : 
    5626           0 :       for (uint32_t i = 0; i < originInfos.Length(); i++) {
    5627           0 :         if (mTemporaryStorageUsage - usage <= mTemporaryStorageLimit) {
    5628           0 :           originInfos.TruncateLength(i);
    5629           0 :           break;
    5630             :         }
    5631             : 
    5632           0 :         usage += originInfos[i]->mUsage;
    5633             :       }
    5634             : 
    5635           0 :       doomedOriginInfos.AppendElements(originInfos);
    5636             :     }
    5637             :   }
    5638             : 
    5639           0 :   for (uint32_t index = 0; index < doomedOriginInfos.Length(); index++) {
    5640           0 :     OriginInfo* doomedOriginInfo = doomedOriginInfos[index];
    5641             : 
    5642             : #ifdef DEBUG
    5643             :     {
    5644           0 :       MutexAutoLock lock(mQuotaMutex);
    5645           0 :       MOZ_ASSERT(!doomedOriginInfo->LockedPersisted());
    5646             :     }
    5647             : #endif
    5648             : 
    5649           0 :     DeleteFilesForOrigin(doomedOriginInfo->mGroupInfo->mPersistenceType,
    5650           0 :                          doomedOriginInfo->mOrigin);
    5651             :   }
    5652             : 
    5653           0 :   nsTArray<OriginParams> doomedOrigins;
    5654             :   {
    5655           0 :     MutexAutoLock lock(mQuotaMutex);
    5656             : 
    5657           0 :     for (uint32_t index = 0; index < doomedOriginInfos.Length(); index++) {
    5658           0 :       OriginInfo* doomedOriginInfo = doomedOriginInfos[index];
    5659             : 
    5660             :       PersistenceType persistenceType =
    5661           0 :         doomedOriginInfo->mGroupInfo->mPersistenceType;
    5662           0 :       nsCString group = doomedOriginInfo->mGroupInfo->mGroup;
    5663           0 :       nsCString origin = doomedOriginInfo->mOrigin;
    5664           0 :       LockedRemoveQuotaForOrigin(persistenceType, group, origin);
    5665             : 
    5666             : #ifdef DEBUG
    5667           0 :       doomedOriginInfos[index] = nullptr;
    5668             : #endif
    5669             : 
    5670           0 :       doomedOrigins.AppendElement(OriginParams(persistenceType, origin));
    5671             :     }
    5672             :   }
    5673             : 
    5674           0 :   for (const OriginParams& doomedOrigin : doomedOrigins) {
    5675           0 :     OriginClearCompleted(doomedOrigin.mPersistenceType,
    5676           0 :                          doomedOrigin.mOrigin);
    5677             :   }
    5678           0 : }
    5679             : 
    5680             : void
    5681           0 : QuotaManager::DeleteFilesForOrigin(PersistenceType aPersistenceType,
    5682             :                                    const nsACString& aOrigin)
    5683             : {
    5684           0 :   nsCOMPtr<nsIFile> directory;
    5685           0 :   nsresult rv = GetDirectoryForOrigin(aPersistenceType, aOrigin,
    5686           0 :                                       getter_AddRefs(directory));
    5687           0 :   NS_ENSURE_SUCCESS_VOID(rv);
    5688             : 
    5689           0 :   rv = directory->Remove(true);
    5690           0 :   if (rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST &&
    5691           0 :       rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
    5692             :     // This should never fail if we've closed all storage connections
    5693             :     // correctly...
    5694           0 :     NS_ERROR("Failed to remove directory!");
    5695             :   }
    5696             : }
    5697             : 
    5698             : void
    5699           0 : QuotaManager::FinalizeOriginEviction(
    5700             :                                   nsTArray<RefPtr<DirectoryLockImpl>>& aLocks)
    5701             : {
    5702           0 :   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
    5703             : 
    5704             :   RefPtr<FinalizeOriginEvictionOp> op =
    5705           0 :     new FinalizeOriginEvictionOp(mOwningThread, aLocks);
    5706             : 
    5707           0 :   if (IsOnIOThread()) {
    5708           0 :     op->RunOnIOThreadImmediately();
    5709             :   } else {
    5710           0 :     op->Dispatch();
    5711             :   }
    5712           0 : }
    5713             : 
    5714             : void
    5715           0 : QuotaManager::ShutdownTimerCallback(nsITimer* aTimer, void* aClosure)
    5716             : {
    5717           0 :   AssertIsOnBackgroundThread();
    5718             : 
    5719           0 :   auto quotaManager = static_cast<QuotaManager*>(aClosure);
    5720           0 :   MOZ_ASSERT(quotaManager);
    5721             : 
    5722             :   NS_WARNING("Some storage operations are taking longer than expected "
    5723           0 :              "during shutdown and will be aborted!");
    5724             : 
    5725             :   // Abort all operations.
    5726           0 :   for (RefPtr<Client>& client : quotaManager->mClients) {
    5727           0 :     client->AbortOperations(NullCString());
    5728             :   }
    5729           0 : }
    5730             : 
    5731             : auto
    5732           0 : QuotaManager::GetDirectoryLockTable(PersistenceType aPersistenceType)
    5733             :   -> DirectoryLockTable&
    5734             : {
    5735           0 :   switch (aPersistenceType) {
    5736             :     case PERSISTENCE_TYPE_TEMPORARY:
    5737           0 :       return mTemporaryDirectoryLockTable;
    5738             :     case PERSISTENCE_TYPE_DEFAULT:
    5739           0 :       return mDefaultDirectoryLockTable;
    5740             : 
    5741             :     case PERSISTENCE_TYPE_PERSISTENT:
    5742             :     case PERSISTENCE_TYPE_INVALID:
    5743             :     default:
    5744           0 :       MOZ_CRASH("Bad persistence type value!");
    5745             :   }
    5746             : }
    5747             : 
    5748             : /*******************************************************************************
    5749             :  * Local class implementations
    5750             :  ******************************************************************************/
    5751             : 
    5752           0 : OriginInfo::OriginInfo(GroupInfo* aGroupInfo, const nsACString& aOrigin,
    5753           0 :                        uint64_t aUsage, int64_t aAccessTime, bool aPersisted)
    5754             :   : mGroupInfo(aGroupInfo), mOrigin(aOrigin), mUsage(aUsage),
    5755           0 :     mAccessTime(aAccessTime), mPersisted(aPersisted)
    5756             : {
    5757           0 :   MOZ_ASSERT(aGroupInfo);
    5758           0 :   MOZ_ASSERT_IF(aPersisted,
    5759             :                 aGroupInfo->mPersistenceType == PERSISTENCE_TYPE_DEFAULT);
    5760             : 
    5761           0 :   MOZ_COUNT_CTOR(OriginInfo);
    5762           0 : }
    5763             : 
    5764             : void
    5765           0 : OriginInfo::LockedDecreaseUsage(int64_t aSize)
    5766             : {
    5767           0 :   AssertCurrentThreadOwnsQuotaMutex();
    5768             : 
    5769           0 :   AssertNoUnderflow(mUsage, aSize);
    5770           0 :   mUsage -= aSize;
    5771             : 
    5772           0 :   if (!LockedPersisted()) {
    5773           0 :     AssertNoUnderflow(mGroupInfo->mUsage, aSize);
    5774           0 :     mGroupInfo->mUsage -= aSize;
    5775             :   }
    5776             : 
    5777           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    5778           0 :   MOZ_ASSERT(quotaManager);
    5779             : 
    5780           0 :   AssertNoUnderflow(quotaManager->mTemporaryStorageUsage, aSize);
    5781           0 :   quotaManager->mTemporaryStorageUsage -= aSize;
    5782           0 : }
    5783             : 
    5784             : void
    5785           0 : OriginInfo::LockedPersist()
    5786             : {
    5787           0 :   AssertCurrentThreadOwnsQuotaMutex();
    5788           0 :   MOZ_ASSERT(mGroupInfo->mPersistenceType == PERSISTENCE_TYPE_DEFAULT);
    5789           0 :   MOZ_ASSERT(!mPersisted);
    5790             : 
    5791           0 :   mPersisted = true;
    5792             : 
    5793             :   // Remove Usage from GroupInfo
    5794           0 :   AssertNoUnderflow(mGroupInfo->mUsage, mUsage);
    5795           0 :   mGroupInfo->mUsage -= mUsage;
    5796           0 : }
    5797             : 
    5798             : already_AddRefed<OriginInfo>
    5799           0 : GroupInfo::LockedGetOriginInfo(const nsACString& aOrigin)
    5800             : {
    5801           0 :   AssertCurrentThreadOwnsQuotaMutex();
    5802             : 
    5803           0 :   for (RefPtr<OriginInfo>& originInfo : mOriginInfos) {
    5804           0 :     if (originInfo->mOrigin == aOrigin) {
    5805           0 :       RefPtr<OriginInfo> result = originInfo;
    5806           0 :       return result.forget();
    5807             :     }
    5808             :   }
    5809             : 
    5810           0 :   return nullptr;
    5811             : }
    5812             : 
    5813             : void
    5814           0 : GroupInfo::LockedAddOriginInfo(OriginInfo* aOriginInfo)
    5815             : {
    5816           0 :   AssertCurrentThreadOwnsQuotaMutex();
    5817             : 
    5818           0 :   NS_ASSERTION(!mOriginInfos.Contains(aOriginInfo),
    5819             :                "Replacing an existing entry!");
    5820           0 :   mOriginInfos.AppendElement(aOriginInfo);
    5821             : 
    5822           0 :   if (!aOriginInfo->LockedPersisted()) {
    5823           0 :     AssertNoOverflow(mUsage, aOriginInfo->mUsage);
    5824           0 :     mUsage += aOriginInfo->mUsage;
    5825             :   }
    5826             : 
    5827           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    5828           0 :   MOZ_ASSERT(quotaManager);
    5829             : 
    5830           0 :   AssertNoOverflow(quotaManager->mTemporaryStorageUsage, aOriginInfo->mUsage);
    5831           0 :   quotaManager->mTemporaryStorageUsage += aOriginInfo->mUsage;
    5832           0 : }
    5833             : 
    5834             : void
    5835           0 : GroupInfo::LockedRemoveOriginInfo(const nsACString& aOrigin)
    5836             : {
    5837           0 :   AssertCurrentThreadOwnsQuotaMutex();
    5838             : 
    5839           0 :   for (uint32_t index = 0; index < mOriginInfos.Length(); index++) {
    5840           0 :     if (mOriginInfos[index]->mOrigin == aOrigin) {
    5841           0 :       if (!mOriginInfos[index]->LockedPersisted()) {
    5842           0 :         AssertNoUnderflow(mUsage, mOriginInfos[index]->mUsage);
    5843           0 :         mUsage -= mOriginInfos[index]->mUsage;
    5844             :       }
    5845             : 
    5846           0 :       QuotaManager* quotaManager = QuotaManager::Get();
    5847           0 :       MOZ_ASSERT(quotaManager);
    5848             : 
    5849           0 :       AssertNoUnderflow(quotaManager->mTemporaryStorageUsage,
    5850           0 :                         mOriginInfos[index]->mUsage);
    5851           0 :       quotaManager->mTemporaryStorageUsage -= mOriginInfos[index]->mUsage;
    5852             : 
    5853           0 :       mOriginInfos.RemoveElementAt(index);
    5854             : 
    5855           0 :       return;
    5856             :     }
    5857             :   }
    5858             : }
    5859             : 
    5860             : void
    5861           0 : GroupInfo::LockedRemoveOriginInfos()
    5862             : {
    5863           0 :   AssertCurrentThreadOwnsQuotaMutex();
    5864             : 
    5865           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    5866           0 :   MOZ_ASSERT(quotaManager);
    5867             : 
    5868           0 :   for (uint32_t index = mOriginInfos.Length(); index > 0; index--) {
    5869           0 :     OriginInfo* originInfo = mOriginInfos[index - 1];
    5870             : 
    5871           0 :     if (!originInfo->LockedPersisted()) {
    5872           0 :       AssertNoUnderflow(mUsage, originInfo->mUsage);
    5873           0 :       mUsage -= originInfo->mUsage;
    5874             :     }
    5875             : 
    5876           0 :     AssertNoUnderflow(quotaManager->mTemporaryStorageUsage, originInfo->mUsage);
    5877           0 :     quotaManager->mTemporaryStorageUsage -= originInfo->mUsage;
    5878             : 
    5879           0 :     mOriginInfos.RemoveElementAt(index - 1);
    5880             :   }
    5881           0 : }
    5882             : 
    5883             : RefPtr<GroupInfo>&
    5884           0 : GroupInfoPair::GetGroupInfoForPersistenceType(PersistenceType aPersistenceType)
    5885             : {
    5886           0 :   switch (aPersistenceType) {
    5887             :     case PERSISTENCE_TYPE_TEMPORARY:
    5888           0 :       return mTemporaryStorageGroupInfo;
    5889             :     case PERSISTENCE_TYPE_DEFAULT:
    5890           0 :       return mDefaultStorageGroupInfo;
    5891             : 
    5892             :     case PERSISTENCE_TYPE_PERSISTENT:
    5893             :     case PERSISTENCE_TYPE_INVALID:
    5894             :     default:
    5895           0 :       MOZ_CRASH("Bad persistence type value!");
    5896             :   }
    5897             : }
    5898             : 
    5899           0 : CollectOriginsHelper::CollectOriginsHelper(mozilla::Mutex& aMutex,
    5900           0 :                                            uint64_t aMinSizeToBeFreed)
    5901             :   : Runnable("dom::quota::CollectOriginsHelper")
    5902             :   , mMinSizeToBeFreed(aMinSizeToBeFreed)
    5903             :   , mMutex(aMutex)
    5904             :   , mCondVar(aMutex, "CollectOriginsHelper::mCondVar")
    5905             :   , mSizeToBeFreed(0)
    5906           0 :   , mWaiting(true)
    5907             : {
    5908           0 :   MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!");
    5909           0 :   mMutex.AssertCurrentThreadOwns();
    5910           0 : }
    5911             : 
    5912             : int64_t
    5913           0 : CollectOriginsHelper::BlockAndReturnOriginsForEviction(
    5914             :                                   nsTArray<RefPtr<DirectoryLockImpl>>& aLocks)
    5915             : {
    5916           0 :   MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!");
    5917           0 :   mMutex.AssertCurrentThreadOwns();
    5918             : 
    5919           0 :   while (mWaiting) {
    5920           0 :     mCondVar.Wait();
    5921             :   }
    5922             : 
    5923           0 :   mLocks.SwapElements(aLocks);
    5924           0 :   return mSizeToBeFreed;
    5925             : }
    5926             : 
    5927             : NS_IMETHODIMP
    5928           0 : CollectOriginsHelper::Run()
    5929             : {
    5930           0 :   AssertIsOnBackgroundThread();
    5931             : 
    5932           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    5933           0 :   NS_ASSERTION(quotaManager, "Shouldn't be null!");
    5934             : 
    5935             :   // We use extra stack vars here to avoid race detector warnings (the same
    5936             :   // memory accessed with and without the lock held).
    5937           0 :   nsTArray<RefPtr<DirectoryLockImpl>> locks;
    5938             :   uint64_t sizeToBeFreed =
    5939           0 :     quotaManager->CollectOriginsForEviction(mMinSizeToBeFreed, locks);
    5940             : 
    5941           0 :   MutexAutoLock lock(mMutex);
    5942             : 
    5943           0 :   NS_ASSERTION(mWaiting, "Huh?!");
    5944             : 
    5945           0 :   mLocks.SwapElements(locks);
    5946           0 :   mSizeToBeFreed = sizeToBeFreed;
    5947           0 :   mWaiting = false;
    5948           0 :   mCondVar.Notify();
    5949             : 
    5950           0 :   return NS_OK;
    5951             : }
    5952             : 
    5953             : /*******************************************************************************
    5954             :  * OriginOperationBase
    5955             :  ******************************************************************************/
    5956             : 
    5957             : NS_IMETHODIMP
    5958           0 : OriginOperationBase::Run()
    5959             : {
    5960             :   nsresult rv;
    5961             : 
    5962           0 :   switch (mState) {
    5963             :     case State_Initial: {
    5964           0 :       rv = Init();
    5965           0 :       break;
    5966             :     }
    5967             : 
    5968             :     case State_Initializing: {
    5969           0 :       rv = InitOnMainThread();
    5970           0 :       break;
    5971             :     }
    5972             : 
    5973             :     case State_FinishingInit: {
    5974           0 :       rv = FinishInit();
    5975           0 :       break;
    5976             :     }
    5977             : 
    5978             :     case State_CreatingQuotaManager: {
    5979           0 :       rv = QuotaManagerOpen();
    5980           0 :       break;
    5981             :     }
    5982             : 
    5983             :     case State_DirectoryOpenPending: {
    5984           0 :       rv = DirectoryOpen();
    5985           0 :       break;
    5986             :     }
    5987             : 
    5988             :     case State_DirectoryWorkOpen: {
    5989           0 :       rv = DirectoryWork();
    5990           0 :       break;
    5991             :     }
    5992             : 
    5993             :     case State_UnblockingOpen: {
    5994           0 :       UnblockOpen();
    5995           0 :       return NS_OK;
    5996             :     }
    5997             : 
    5998             :     default:
    5999           0 :       MOZ_CRASH("Bad state!");
    6000             :   }
    6001             : 
    6002           0 :   if (NS_WARN_IF(NS_FAILED(rv)) && mState != State_UnblockingOpen) {
    6003           0 :     Finish(rv);
    6004             :   }
    6005             : 
    6006           0 :   return NS_OK;
    6007             : }
    6008             : 
    6009             : nsresult
    6010           0 : OriginOperationBase::DirectoryOpen()
    6011             : {
    6012           0 :   AssertIsOnOwningThread();
    6013           0 :   MOZ_ASSERT(mState == State_DirectoryOpenPending);
    6014             : 
    6015           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    6016           0 :   if (NS_WARN_IF(!quotaManager)) {
    6017           0 :     return NS_ERROR_FAILURE;
    6018             :   }
    6019             : 
    6020             :   // Must set this before dispatching otherwise we will race with the IO thread.
    6021           0 :   AdvanceState();
    6022             : 
    6023           0 :   nsresult rv = quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
    6024           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    6025           0 :     return NS_ERROR_FAILURE;
    6026             :   }
    6027             : 
    6028           0 :   return NS_OK;
    6029             : }
    6030             : 
    6031             : void
    6032           0 : OriginOperationBase::Finish(nsresult aResult)
    6033             : {
    6034           0 :   if (NS_SUCCEEDED(mResultCode)) {
    6035           0 :     mResultCode = aResult;
    6036             :   }
    6037             : 
    6038             :   // Must set mState before dispatching otherwise we will race with the main
    6039             :   // thread.
    6040           0 :   mState = State_UnblockingOpen;
    6041             : 
    6042           0 :   MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL));
    6043           0 : }
    6044             : 
    6045             : nsresult
    6046           0 : OriginOperationBase::Init()
    6047             : {
    6048           0 :   AssertIsOnOwningThread();
    6049           0 :   MOZ_ASSERT(mState == State_Initial);
    6050             : 
    6051           0 :   AdvanceState();
    6052             : 
    6053           0 :   if (mNeedsMainThreadInit) {
    6054           0 :     MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
    6055             :   } else {
    6056           0 :     AdvanceState();
    6057           0 :     MOZ_ALWAYS_SUCCEEDS(Run());
    6058             :   }
    6059             : 
    6060           0 :   return NS_OK;
    6061             : }
    6062             : 
    6063             : nsresult
    6064           0 : OriginOperationBase::InitOnMainThread()
    6065             : {
    6066           0 :   MOZ_ASSERT(NS_IsMainThread());
    6067           0 :   MOZ_ASSERT(mState == State_Initializing);
    6068             : 
    6069           0 :   nsresult rv = DoInitOnMainThread();
    6070           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    6071           0 :     return rv;
    6072             :   }
    6073             : 
    6074           0 :   AdvanceState();
    6075             : 
    6076           0 :   MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL));
    6077             : 
    6078           0 :   return NS_OK;
    6079             : }
    6080             : 
    6081             : nsresult
    6082           0 : OriginOperationBase::FinishInit()
    6083             : {
    6084           0 :   AssertIsOnOwningThread();
    6085           0 :   MOZ_ASSERT(mState == State_FinishingInit);
    6086             : 
    6087           0 :   if (QuotaManager::IsShuttingDown()) {
    6088           0 :     return NS_ERROR_FAILURE;
    6089             :   }
    6090             : 
    6091           0 :   AdvanceState();
    6092             : 
    6093           0 :   if (mNeedsQuotaManagerInit && !QuotaManager::Get()) {
    6094           0 :     QuotaManager::GetOrCreate(this);
    6095             :   } else {
    6096           0 :     Open();
    6097             :   }
    6098             : 
    6099           0 :   return NS_OK;
    6100             : }
    6101             : 
    6102             : nsresult
    6103           0 : OriginOperationBase::QuotaManagerOpen()
    6104             : {
    6105           0 :   AssertIsOnOwningThread();
    6106           0 :   MOZ_ASSERT(mState == State_CreatingQuotaManager);
    6107             : 
    6108           0 :   if (NS_WARN_IF(!QuotaManager::Get())) {
    6109           0 :     return NS_ERROR_FAILURE;
    6110             :   }
    6111             : 
    6112           0 :   Open();
    6113             : 
    6114           0 :   return NS_OK;
    6115             : }
    6116             : 
    6117             : nsresult
    6118           0 : OriginOperationBase::DirectoryWork()
    6119             : {
    6120           0 :   AssertIsOnIOThread();
    6121           0 :   MOZ_ASSERT(mState == State_DirectoryWorkOpen);
    6122             : 
    6123           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    6124           0 :   if (NS_WARN_IF(!quotaManager)) {
    6125           0 :     return NS_ERROR_FAILURE;
    6126             :   }
    6127             : 
    6128             :   nsresult rv;
    6129             : 
    6130           0 :   if (mNeedsQuotaManagerInit) {
    6131           0 :     rv = quotaManager->EnsureStorageIsInitialized();
    6132           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    6133           0 :       return rv;
    6134             :     }
    6135             :   }
    6136             : 
    6137           0 :   rv = DoDirectoryWork(quotaManager);
    6138           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    6139           0 :     return rv;
    6140             :   }
    6141             : 
    6142             :   // Must set mState before dispatching otherwise we will race with the owning
    6143             :   // thread.
    6144           0 :   AdvanceState();
    6145             : 
    6146           0 :   MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL));
    6147             : 
    6148           0 :   return NS_OK;
    6149             : }
    6150             : 
    6151             : void
    6152           0 : FinalizeOriginEvictionOp::Dispatch()
    6153             : {
    6154           0 :   MOZ_ASSERT(!NS_IsMainThread());
    6155           0 :   MOZ_ASSERT(GetState() == State_Initial);
    6156             : 
    6157           0 :   SetState(State_DirectoryOpenPending);
    6158             : 
    6159           0 :   MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL));
    6160           0 : }
    6161             : 
    6162             : void
    6163           0 : FinalizeOriginEvictionOp::RunOnIOThreadImmediately()
    6164             : {
    6165           0 :   AssertIsOnIOThread();
    6166           0 :   MOZ_ASSERT(GetState() == State_Initial);
    6167             : 
    6168           0 :   SetState(State_DirectoryWorkOpen);
    6169             : 
    6170           0 :   MOZ_ALWAYS_SUCCEEDS(this->Run());
    6171           0 : }
    6172             : 
    6173             : void
    6174           0 : FinalizeOriginEvictionOp::Open()
    6175             : {
    6176           0 :   MOZ_CRASH("Shouldn't get here!");
    6177             : }
    6178             : 
    6179             : nsresult
    6180           0 : FinalizeOriginEvictionOp::DoDirectoryWork(QuotaManager* aQuotaManager)
    6181             : {
    6182           0 :   AssertIsOnIOThread();
    6183             : 
    6184           0 :   AUTO_PROFILER_LABEL("FinalizeOriginEvictionOp::DoDirectoryWork", OTHER);
    6185             : 
    6186           0 :   for (RefPtr<DirectoryLockImpl>& lock : mLocks) {
    6187           0 :     aQuotaManager->OriginClearCompleted(lock->GetPersistenceType().Value(),
    6188           0 :                                         lock->GetOriginScope().GetOrigin());
    6189             :   }
    6190             : 
    6191           0 :   return NS_OK;
    6192             : }
    6193             : 
    6194             : void
    6195           0 : FinalizeOriginEvictionOp::UnblockOpen()
    6196             : {
    6197           0 :   AssertIsOnOwningThread();
    6198           0 :   MOZ_ASSERT(GetState() == State_UnblockingOpen);
    6199             : 
    6200             : #ifdef DEBUG
    6201           0 :   NoteActorDestroyed();
    6202             : #endif
    6203             : 
    6204           0 :   mLocks.Clear();
    6205             : 
    6206           0 :   AdvanceState();
    6207           0 : }
    6208             : 
    6209           0 : NS_IMPL_ISUPPORTS_INHERITED0(NormalOriginOperationBase, Runnable)
    6210             : 
    6211             : void
    6212           0 : NormalOriginOperationBase::Open()
    6213             : {
    6214           0 :   AssertIsOnOwningThread();
    6215           0 :   MOZ_ASSERT(GetState() == State_CreatingQuotaManager);
    6216           0 :   MOZ_ASSERT(QuotaManager::Get());
    6217             : 
    6218           0 :   AdvanceState();
    6219             : 
    6220           0 :   QuotaManager::Get()->OpenDirectoryInternal(mPersistenceType,
    6221             :                                              mOriginScope,
    6222           0 :                                              Nullable<Client::Type>(),
    6223           0 :                                              mExclusive,
    6224           0 :                                              this);
    6225           0 : }
    6226             : 
    6227             : void
    6228           0 : NormalOriginOperationBase::UnblockOpen()
    6229             : {
    6230           0 :   AssertIsOnOwningThread();
    6231           0 :   MOZ_ASSERT(GetState() == State_UnblockingOpen);
    6232             : 
    6233           0 :   SendResults();
    6234             : 
    6235           0 :   mDirectoryLock = nullptr;
    6236             : 
    6237           0 :   AdvanceState();
    6238           0 : }
    6239             : 
    6240             : void
    6241           0 : NormalOriginOperationBase::DirectoryLockAcquired(DirectoryLock* aLock)
    6242             : {
    6243           0 :   AssertIsOnOwningThread();
    6244           0 :   MOZ_ASSERT(aLock);
    6245           0 :   MOZ_ASSERT(GetState() == State_DirectoryOpenPending);
    6246           0 :   MOZ_ASSERT(!mDirectoryLock);
    6247             : 
    6248           0 :   mDirectoryLock = aLock;
    6249             : 
    6250           0 :   nsresult rv = DirectoryOpen();
    6251           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    6252           0 :     Finish(rv);
    6253           0 :     return;
    6254             :   }
    6255             : }
    6256             : 
    6257             : void
    6258           0 : NormalOriginOperationBase::DirectoryLockFailed()
    6259             : {
    6260           0 :   AssertIsOnOwningThread();
    6261           0 :   MOZ_ASSERT(GetState() == State_DirectoryOpenPending);
    6262           0 :   MOZ_ASSERT(!mDirectoryLock);
    6263             : 
    6264           0 :   Finish(NS_ERROR_FAILURE);
    6265           0 : }
    6266             : 
    6267             : nsresult
    6268           0 : SaveOriginAccessTimeOp::DoDirectoryWork(QuotaManager* aQuotaManager)
    6269             : {
    6270           0 :   AssertIsOnIOThread();
    6271           0 :   MOZ_ASSERT(!mPersistenceType.IsNull());
    6272           0 :   MOZ_ASSERT(mOriginScope.IsOrigin());
    6273             : 
    6274           0 :   AUTO_PROFILER_LABEL("SaveOriginAccessTimeOp::DoDirectoryWork", OTHER);
    6275             : 
    6276           0 :   nsCOMPtr<nsIFile> file;
    6277             :   nsresult rv =
    6278           0 :     aQuotaManager->GetDirectoryForOrigin(mPersistenceType.Value(),
    6279             :                                          mOriginScope.GetOrigin(),
    6280           0 :                                          getter_AddRefs(file));
    6281           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    6282           0 :     return rv;
    6283             :   }
    6284             : 
    6285           0 :   rv = file->Append(NS_LITERAL_STRING(METADATA_V2_FILE_NAME));
    6286           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    6287           0 :     return rv;
    6288             :   }
    6289             : 
    6290           0 :   nsCOMPtr<nsIBinaryOutputStream> stream;
    6291           0 :   rv = GetBinaryOutputStream(file, kUpdateFileFlag, getter_AddRefs(stream));
    6292           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    6293           0 :     return rv;
    6294             :   }
    6295             : 
    6296             :   // The origin directory may not exist anymore.
    6297           0 :   if (stream) {
    6298           0 :     rv = stream->Write64(mTimestamp);
    6299           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    6300           0 :       return rv;
    6301             :     }
    6302             :   }
    6303             : 
    6304           0 :   return NS_OK;
    6305             : }
    6306             : 
    6307             : void
    6308           0 : SaveOriginAccessTimeOp::SendResults()
    6309             : {
    6310             : #ifdef DEBUG
    6311           0 :   NoteActorDestroyed();
    6312             : #endif
    6313           0 : }
    6314             : 
    6315             : /*******************************************************************************
    6316             :  * Quota
    6317             :  ******************************************************************************/
    6318             : 
    6319           0 : Quota::Quota()
    6320             : #ifdef DEBUG
    6321           0 :   : mActorDestroyed(false)
    6322             : #endif
    6323             : {
    6324           0 : }
    6325             : 
    6326           0 : Quota::~Quota()
    6327             : {
    6328           0 :   MOZ_ASSERT(mActorDestroyed);
    6329           0 : }
    6330             : 
    6331             : void
    6332           0 : Quota::StartIdleMaintenance()
    6333             : {
    6334           0 :   AssertIsOnBackgroundThread();
    6335           0 :   MOZ_ASSERT(!QuotaManager::IsShuttingDown());
    6336             : 
    6337           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    6338           0 :   if (NS_WARN_IF(!quotaManager)) {
    6339           0 :     return;
    6340             :   }
    6341             : 
    6342           0 :   quotaManager->StartIdleMaintenance();
    6343             : }
    6344             : 
    6345             : void
    6346           0 : Quota::ActorDestroy(ActorDestroyReason aWhy)
    6347             : {
    6348           0 :   AssertIsOnBackgroundThread();
    6349             : #ifdef DEBUG
    6350           0 :   MOZ_ASSERT(!mActorDestroyed);
    6351           0 :   mActorDestroyed = true;
    6352             : #endif
    6353           0 : }
    6354             : 
    6355             : PQuotaUsageRequestParent*
    6356           0 : Quota::AllocPQuotaUsageRequestParent(const UsageRequestParams& aParams)
    6357             : {
    6358           0 :   AssertIsOnBackgroundThread();
    6359           0 :   MOZ_ASSERT(aParams.type() != UsageRequestParams::T__None);
    6360             : 
    6361           0 :   RefPtr<QuotaUsageRequestBase> actor;
    6362             : 
    6363           0 :   switch (aParams.type()) {
    6364             :     case UsageRequestParams::TAllUsageParams:
    6365           0 :       actor = new GetUsageOp(aParams);
    6366           0 :       break;
    6367             : 
    6368             :     case UsageRequestParams::TOriginUsageParams:
    6369           0 :       actor = new GetOriginUsageOp(aParams);
    6370           0 :       break;
    6371             : 
    6372             :     default:
    6373           0 :       MOZ_CRASH("Should never get here!");
    6374             :   }
    6375             : 
    6376           0 :   MOZ_ASSERT(actor);
    6377             : 
    6378             :   // Transfer ownership to IPDL.
    6379           0 :   return actor.forget().take();
    6380             : }
    6381             : 
    6382             : mozilla::ipc::IPCResult
    6383           0 : Quota::RecvPQuotaUsageRequestConstructor(PQuotaUsageRequestParent* aActor,
    6384             :                                          const UsageRequestParams& aParams)
    6385             : {
    6386           0 :   AssertIsOnBackgroundThread();
    6387           0 :   MOZ_ASSERT(aActor);
    6388           0 :   MOZ_ASSERT(aParams.type() != UsageRequestParams::T__None);
    6389             : 
    6390           0 :   auto* op = static_cast<QuotaUsageRequestBase*>(aActor);
    6391             : 
    6392           0 :   if (NS_WARN_IF(!op->Init(this))) {
    6393           0 :     return IPC_FAIL_NO_REASON(this);
    6394             :   }
    6395             : 
    6396           0 :   op->RunImmediately();
    6397           0 :   return IPC_OK();
    6398             : }
    6399             : 
    6400             : bool
    6401           0 : Quota::DeallocPQuotaUsageRequestParent(PQuotaUsageRequestParent* aActor)
    6402             : {
    6403           0 :   AssertIsOnBackgroundThread();
    6404           0 :   MOZ_ASSERT(aActor);
    6405             : 
    6406             :   // Transfer ownership back from IPDL.
    6407             :   RefPtr<QuotaUsageRequestBase> actor =
    6408           0 :     dont_AddRef(static_cast<QuotaUsageRequestBase*>(aActor));
    6409           0 :   return true;
    6410             : }
    6411             : 
    6412             : PQuotaRequestParent*
    6413           0 : Quota::AllocPQuotaRequestParent(const RequestParams& aParams)
    6414             : {
    6415           0 :   AssertIsOnBackgroundThread();
    6416           0 :   MOZ_ASSERT(aParams.type() != RequestParams::T__None);
    6417             : 
    6418           0 :   if (aParams.type() == RequestParams::TClearDataParams) {
    6419           0 :     PBackgroundParent* actor = Manager();
    6420           0 :     MOZ_ASSERT(actor);
    6421             : 
    6422           0 :     if (BackgroundParent::IsOtherProcessActor(actor)) {
    6423           0 :       ASSERT_UNLESS_FUZZING();
    6424             :       return nullptr;
    6425             :     }
    6426             :   }
    6427             : 
    6428           0 :   RefPtr<QuotaRequestBase> actor;
    6429             : 
    6430           0 :   switch (aParams.type()) {
    6431             :     case RequestParams::TInitParams:
    6432           0 :       actor = new InitOp();
    6433           0 :       break;
    6434             : 
    6435             :     case RequestParams::TInitOriginParams:
    6436           0 :       actor = new InitOriginOp(aParams);
    6437           0 :       break;
    6438             : 
    6439             :     case RequestParams::TClearOriginParams:
    6440           0 :       actor = new ClearOriginOp(aParams);
    6441           0 :       break;
    6442             : 
    6443             :     case RequestParams::TClearDataParams:
    6444           0 :       actor = new ClearDataOp(aParams);
    6445           0 :       break;
    6446             : 
    6447             :     case RequestParams::TClearAllParams:
    6448           0 :       actor = new ResetOrClearOp(/* aClear */ true);
    6449           0 :       break;
    6450             : 
    6451             :     case RequestParams::TResetAllParams:
    6452           0 :       actor = new ResetOrClearOp(/* aClear */ false);
    6453           0 :       break;
    6454             : 
    6455             :     case RequestParams::TPersistedParams:
    6456           0 :       actor = new PersistedOp(aParams);
    6457           0 :       break;
    6458             : 
    6459             :     case RequestParams::TPersistParams:
    6460           0 :       actor = new PersistOp(aParams);
    6461           0 :       break;
    6462             : 
    6463             :     default:
    6464           0 :       MOZ_CRASH("Should never get here!");
    6465             :   }
    6466             : 
    6467           0 :   MOZ_ASSERT(actor);
    6468             : 
    6469             :   // Transfer ownership to IPDL.
    6470           0 :   return actor.forget().take();
    6471             : }
    6472             : 
    6473             : mozilla::ipc::IPCResult
    6474           0 : Quota::RecvPQuotaRequestConstructor(PQuotaRequestParent* aActor,
    6475             :                                     const RequestParams& aParams)
    6476             : {
    6477           0 :   AssertIsOnBackgroundThread();
    6478           0 :   MOZ_ASSERT(aActor);
    6479           0 :   MOZ_ASSERT(aParams.type() != RequestParams::T__None);
    6480             : 
    6481           0 :   auto* op = static_cast<QuotaRequestBase*>(aActor);
    6482             : 
    6483           0 :   if (NS_WARN_IF(!op->Init(this))) {
    6484           0 :     return IPC_FAIL_NO_REASON(this);
    6485             :   }
    6486             : 
    6487           0 :   op->RunImmediately();
    6488           0 :   return IPC_OK();
    6489             : }
    6490             : 
    6491             : bool
    6492           0 : Quota::DeallocPQuotaRequestParent(PQuotaRequestParent* aActor)
    6493             : {
    6494           0 :   AssertIsOnBackgroundThread();
    6495           0 :   MOZ_ASSERT(aActor);
    6496             : 
    6497             :   // Transfer ownership back from IPDL.
    6498             :   RefPtr<QuotaRequestBase> actor =
    6499           0 :     dont_AddRef(static_cast<QuotaRequestBase*>(aActor));
    6500           0 :   return true;
    6501             : }
    6502             : 
    6503             : mozilla::ipc::IPCResult
    6504           0 : Quota::RecvStartIdleMaintenance()
    6505             : {
    6506           0 :   AssertIsOnBackgroundThread();
    6507             : 
    6508           0 :   PBackgroundParent* actor = Manager();
    6509           0 :   MOZ_ASSERT(actor);
    6510             : 
    6511           0 :   if (BackgroundParent::IsOtherProcessActor(actor)) {
    6512           0 :     ASSERT_UNLESS_FUZZING();
    6513             :     return IPC_FAIL_NO_REASON(this);
    6514             :   }
    6515             : 
    6516           0 :   if (QuotaManager::IsShuttingDown()) {
    6517           0 :     return IPC_OK();
    6518             :   }
    6519             : 
    6520           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    6521           0 :   if (!quotaManager) {
    6522             :     nsCOMPtr<nsIRunnable> callback =
    6523           0 :       NewRunnableMethod("dom::quota::Quota::StartIdleMaintenance",
    6524             :                         this,
    6525           0 :                         &Quota::StartIdleMaintenance);
    6526             : 
    6527           0 :     QuotaManager::GetOrCreate(callback);
    6528           0 :     return IPC_OK();
    6529             :   }
    6530             : 
    6531           0 :   quotaManager->StartIdleMaintenance();
    6532             : 
    6533           0 :   return IPC_OK();
    6534             : }
    6535             : 
    6536             : mozilla::ipc::IPCResult
    6537           0 : Quota::RecvStopIdleMaintenance()
    6538             : {
    6539           0 :   AssertIsOnBackgroundThread();
    6540             : 
    6541           0 :   PBackgroundParent* actor = Manager();
    6542           0 :   MOZ_ASSERT(actor);
    6543             : 
    6544           0 :   if (BackgroundParent::IsOtherProcessActor(actor)) {
    6545           0 :     ASSERT_UNLESS_FUZZING();
    6546             :     return IPC_FAIL_NO_REASON(this);
    6547             :   }
    6548             : 
    6549           0 :   if (QuotaManager::IsShuttingDown()) {
    6550           0 :     return IPC_OK();
    6551             :   }
    6552             : 
    6553           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    6554           0 :   if (!quotaManager) {
    6555           0 :     return IPC_OK();
    6556             :   }
    6557             : 
    6558           0 :   quotaManager->StopIdleMaintenance();
    6559             : 
    6560           0 :   return IPC_OK();
    6561             : }
    6562             : 
    6563             : bool
    6564           0 : QuotaUsageRequestBase::Init(Quota* aQuota)
    6565             : {
    6566           0 :   AssertIsOnOwningThread();
    6567           0 :   MOZ_ASSERT(aQuota);
    6568             : 
    6569           0 :   mNeedsQuotaManagerInit = true;
    6570             : 
    6571           0 :   return true;
    6572             : }
    6573             : 
    6574             : nsresult
    6575           0 : QuotaUsageRequestBase::GetUsageForOrigin(QuotaManager* aQuotaManager,
    6576             :                                          PersistenceType aPersistenceType,
    6577             :                                          const nsACString& aGroup,
    6578             :                                          const nsACString& aOrigin,
    6579             :                                          UsageInfo* aUsageInfo)
    6580             : {
    6581           0 :   AssertIsOnIOThread();
    6582           0 :   MOZ_ASSERT(aQuotaManager);
    6583           0 :   MOZ_ASSERT(aUsageInfo);
    6584           0 :   MOZ_ASSERT(aUsageInfo->TotalUsage() == 0);
    6585             : 
    6586           0 :   nsCOMPtr<nsIFile> directory;
    6587           0 :   nsresult rv = aQuotaManager->GetDirectoryForOrigin(aPersistenceType,
    6588             :                                                      aOrigin,
    6589           0 :                                                      getter_AddRefs(directory));
    6590           0 :   NS_ENSURE_SUCCESS(rv, rv);
    6591             : 
    6592             :   bool exists;
    6593           0 :   rv = directory->Exists(&exists);
    6594           0 :   NS_ENSURE_SUCCESS(rv, rv);
    6595             : 
    6596             :   // If the directory exists then enumerate all the files inside, adding up
    6597             :   // the sizes to get the final usage statistic.
    6598           0 :   if (exists && !mCanceled) {
    6599             :     bool initialized;
    6600             : 
    6601           0 :     if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
    6602           0 :       initialized = aQuotaManager->IsOriginInitialized(aOrigin);
    6603             :     } else {
    6604           0 :       initialized = aQuotaManager->IsTemporaryStorageInitialized();
    6605             :     }
    6606             : 
    6607           0 :     nsCOMPtr<nsISimpleEnumerator> entries;
    6608           0 :     rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
    6609           0 :     NS_ENSURE_SUCCESS(rv, rv);
    6610             : 
    6611             :     bool hasMore;
    6612           0 :     while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
    6613           0 :            hasMore && !mCanceled) {
    6614           0 :       nsCOMPtr<nsISupports> entry;
    6615           0 :       rv = entries->GetNext(getter_AddRefs(entry));
    6616           0 :       NS_ENSURE_SUCCESS(rv, rv);
    6617             : 
    6618           0 :       nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
    6619           0 :       NS_ENSURE_TRUE(file, NS_NOINTERFACE);
    6620             : 
    6621             :       bool isDirectory;
    6622           0 :       rv = file->IsDirectory(&isDirectory);
    6623           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    6624           0 :         return rv;
    6625             :       }
    6626             : 
    6627           0 :       nsString leafName;
    6628           0 :       rv = file->GetLeafName(leafName);
    6629           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    6630           0 :         return rv;
    6631             :       }
    6632             : 
    6633           0 :       if (!isDirectory) {
    6634             :         // We are maintaining existing behavior here (failing if the origin is
    6635             :         // not yet initialized or just continuing otherwise).
    6636             :         // This can possibly be used by developers to add temporary backups into
    6637             :         // origin directories without losing get usage functionality.
    6638           0 :         if (IsOriginMetadata(leafName)) {
    6639           0 :           continue;
    6640             :         }
    6641             : 
    6642           0 :         if (IsTempMetadata(leafName)) {
    6643           0 :           if (!initialized) {
    6644           0 :             rv = file->Remove(/* recursive */ false);
    6645           0 :             if (NS_WARN_IF(NS_FAILED(rv))) {
    6646           0 :               return rv;
    6647             :             }
    6648             :           }
    6649             : 
    6650           0 :           continue;
    6651             :         }
    6652             : 
    6653           0 :         UNKNOWN_FILE_WARNING(leafName);
    6654           0 :         if (!initialized) {
    6655           0 :           return NS_ERROR_UNEXPECTED;
    6656             :         }
    6657           0 :         continue;
    6658             :       }
    6659             : 
    6660             :       Client::Type clientType;
    6661           0 :       rv = Client::TypeFromText(leafName, clientType);
    6662           0 :       if (NS_FAILED(rv)) {
    6663           0 :         UNKNOWN_FILE_WARNING(leafName);
    6664           0 :         if (!initialized) {
    6665           0 :           return NS_ERROR_UNEXPECTED;
    6666             :         }
    6667           0 :         continue;
    6668             :       }
    6669             : 
    6670           0 :       Client* client = aQuotaManager->GetClient(clientType);
    6671           0 :       MOZ_ASSERT(client);
    6672             : 
    6673           0 :       if (initialized) {
    6674           0 :         rv = client->GetUsageForOrigin(aPersistenceType,
    6675             :                                        aGroup,
    6676             :                                        aOrigin,
    6677             :                                        mCanceled,
    6678           0 :                                        aUsageInfo);
    6679             :       }
    6680             :       else {
    6681           0 :         rv = client->InitOrigin(aPersistenceType,
    6682             :                                 aGroup,
    6683             :                                 aOrigin,
    6684             :                                 mCanceled,
    6685           0 :                                 aUsageInfo);
    6686             :       }
    6687           0 :       NS_ENSURE_SUCCESS(rv, rv);
    6688             :     }
    6689             :   }
    6690             : 
    6691           0 :   return NS_OK;
    6692             : }
    6693             : 
    6694             : void
    6695           0 : QuotaUsageRequestBase::SendResults()
    6696             : {
    6697           0 :   AssertIsOnOwningThread();
    6698             : 
    6699           0 :   if (IsActorDestroyed()) {
    6700           0 :     if (NS_SUCCEEDED(mResultCode)) {
    6701           0 :       mResultCode = NS_ERROR_FAILURE;
    6702             :     }
    6703             :   } else {
    6704           0 :     if (mCanceled) {
    6705           0 :       mResultCode = NS_ERROR_FAILURE;
    6706             :     }
    6707             : 
    6708           0 :     UsageRequestResponse response;
    6709             : 
    6710           0 :     if (NS_SUCCEEDED(mResultCode)) {
    6711           0 :       GetResponse(response);
    6712             :     } else {
    6713           0 :       response = mResultCode;
    6714             :     }
    6715             : 
    6716           0 :     Unused << PQuotaUsageRequestParent::Send__delete__(this, response);
    6717             :   }
    6718           0 : }
    6719             : 
    6720             : void
    6721           0 : QuotaUsageRequestBase::ActorDestroy(ActorDestroyReason aWhy)
    6722             : {
    6723           0 :   AssertIsOnOwningThread();
    6724             : 
    6725           0 :   NoteActorDestroyed();
    6726           0 : }
    6727             : 
    6728             : mozilla::ipc::IPCResult
    6729           0 : QuotaUsageRequestBase::RecvCancel()
    6730             : {
    6731           0 :   AssertIsOnOwningThread();
    6732             : 
    6733           0 :   if (mCanceled.exchange(true)) {
    6734           0 :     NS_WARNING("Canceled more than once?!");
    6735           0 :     return IPC_FAIL_NO_REASON(this);
    6736             :   }
    6737             : 
    6738           0 :   return IPC_OK();
    6739             : }
    6740             : 
    6741           0 : GetUsageOp::GetUsageOp(const UsageRequestParams& aParams)
    6742           0 :   : mGetAll(aParams.get_AllUsageParams().getAll())
    6743             : {
    6744           0 :   AssertIsOnOwningThread();
    6745           0 :   MOZ_ASSERT(aParams.type() == UsageRequestParams::TAllUsageParams);
    6746           0 : }
    6747             : 
    6748             : nsresult
    6749           0 : GetUsageOp::TraverseRepository(QuotaManager* aQuotaManager,
    6750             :                                PersistenceType aPersistenceType)
    6751             : {
    6752           0 :   AssertIsOnIOThread();
    6753           0 :   MOZ_ASSERT(aQuotaManager);
    6754             : 
    6755             :   nsresult rv;
    6756             : 
    6757             :   nsCOMPtr<nsIFile> directory =
    6758           0 :     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    6759           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    6760           0 :     return rv;
    6761             :   }
    6762             : 
    6763           0 :   rv = directory->InitWithPath(aQuotaManager->GetStoragePath(aPersistenceType));
    6764           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    6765           0 :     return rv;
    6766             :   }
    6767             : 
    6768             :   bool exists;
    6769           0 :   rv = directory->Exists(&exists);
    6770           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    6771           0 :     return rv;
    6772             :   }
    6773             : 
    6774           0 :   if (!exists) {
    6775           0 :     return NS_OK;
    6776             :   }
    6777             : 
    6778           0 :   nsCOMPtr<nsISimpleEnumerator> entries;
    6779           0 :   rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
    6780           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    6781           0 :     return rv;
    6782             :   }
    6783             : 
    6784           0 :   bool persistent = aPersistenceType == PERSISTENCE_TYPE_PERSISTENT;
    6785             : 
    6786             :   bool hasMore;
    6787           0 :   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
    6788           0 :          hasMore && !mCanceled) {
    6789           0 :     nsCOMPtr<nsISupports> entry;
    6790           0 :     rv = entries->GetNext(getter_AddRefs(entry));
    6791           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    6792           0 :       return rv;
    6793             :     }
    6794             : 
    6795           0 :     nsCOMPtr<nsIFile> originDir = do_QueryInterface(entry);
    6796           0 :     MOZ_ASSERT(originDir);
    6797             : 
    6798             :     bool isDirectory;
    6799           0 :     rv = originDir->IsDirectory(&isDirectory);
    6800           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    6801           0 :       return rv;
    6802             :     }
    6803             : 
    6804           0 :     if (!isDirectory) {
    6805           0 :       nsString leafName;
    6806           0 :       rv = originDir->GetLeafName(leafName);
    6807           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    6808           0 :         return rv;
    6809             :       }
    6810             : 
    6811           0 :       if (!IsOSMetadata(leafName)) {
    6812           0 :         UNKNOWN_FILE_WARNING(leafName);
    6813             :       }
    6814           0 :       continue;
    6815             :     }
    6816             : 
    6817             :     int64_t timestamp;
    6818             :     bool persisted;
    6819           0 :     nsCString suffix;
    6820           0 :     nsCString group;
    6821           0 :     nsCString origin;
    6822           0 :     rv = aQuotaManager->GetDirectoryMetadata2WithRestore(originDir,
    6823             :                                                          persistent,
    6824             :                                                          &timestamp,
    6825             :                                                          &persisted,
    6826             :                                                          suffix,
    6827             :                                                          group,
    6828             :                                                          origin);
    6829           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    6830           0 :       return rv;
    6831             :     }
    6832             : 
    6833           0 :     if (!mGetAll && aQuotaManager->IsOriginInternal(origin)) {
    6834           0 :       continue;
    6835             :     }
    6836             : 
    6837             :     OriginUsage* originUsage;
    6838             : 
    6839             :     // We can't store pointers to OriginUsage objects in the hashtable
    6840             :     // since AppendElement() reallocates its internal array buffer as number
    6841             :     // of elements grows.
    6842             :     uint32_t index;
    6843           0 :     if (mOriginUsagesIndex.Get(origin, &index)) {
    6844           0 :       originUsage = &mOriginUsages[index];
    6845             :     } else {
    6846           0 :       index = mOriginUsages.Length();
    6847             : 
    6848           0 :       originUsage = mOriginUsages.AppendElement();
    6849             : 
    6850           0 :       originUsage->origin() = origin;
    6851           0 :       originUsage->persisted() = false;
    6852           0 :       originUsage->usage() = 0;
    6853             : 
    6854           0 :       mOriginUsagesIndex.Put(origin, index);
    6855             :     }
    6856             : 
    6857           0 :     if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) {
    6858           0 :       originUsage->persisted() = persisted;
    6859             :     }
    6860             : 
    6861           0 :     UsageInfo usageInfo;
    6862           0 :     rv = GetUsageForOrigin(aQuotaManager,
    6863             :                            aPersistenceType,
    6864             :                            group,
    6865             :                            origin,
    6866             :                            &usageInfo);
    6867           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    6868           0 :       return rv;
    6869             :     }
    6870             : 
    6871           0 :     originUsage->usage() = originUsage->usage() + usageInfo.TotalUsage();
    6872             :   }
    6873           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    6874           0 :     return rv;
    6875             :   }
    6876             : 
    6877           0 :   return NS_OK;
    6878             : }
    6879             : 
    6880             : nsresult
    6881           0 : GetUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager)
    6882             : {
    6883           0 :   AssertIsOnIOThread();
    6884             : 
    6885           0 :   AUTO_PROFILER_LABEL("GetUsageOp::DoDirectoryWork", OTHER);
    6886             : 
    6887             :   nsresult rv;
    6888             : 
    6889           0 :   for (const PersistenceType type : kAllPersistenceTypes) {
    6890           0 :     rv = TraverseRepository(aQuotaManager, type);
    6891           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    6892           0 :       return rv;
    6893             :     }
    6894             :   }
    6895             : 
    6896           0 :   return NS_OK;
    6897             : }
    6898             : 
    6899             : void
    6900           0 : GetUsageOp::GetResponse(UsageRequestResponse& aResponse)
    6901             : {
    6902           0 :   AssertIsOnOwningThread();
    6903             : 
    6904           0 :   aResponse = AllUsageResponse();
    6905             : 
    6906           0 :   if (!mOriginUsages.IsEmpty()) {
    6907             :     nsTArray<OriginUsage>& originUsages =
    6908           0 :       aResponse.get_AllUsageResponse().originUsages();
    6909             : 
    6910           0 :     mOriginUsages.SwapElements(originUsages);
    6911             :   }
    6912           0 : }
    6913             : 
    6914           0 : GetOriginUsageOp::GetOriginUsageOp(const UsageRequestParams& aParams)
    6915           0 :   : mParams(aParams.get_OriginUsageParams())
    6916           0 :   , mGetGroupUsage(aParams.get_OriginUsageParams().getGroupUsage())
    6917             : {
    6918           0 :   AssertIsOnOwningThread();
    6919           0 :   MOZ_ASSERT(aParams.type() == UsageRequestParams::TOriginUsageParams);
    6920           0 : }
    6921             : 
    6922             : bool
    6923           0 : GetOriginUsageOp::Init(Quota* aQuota)
    6924             : {
    6925           0 :   AssertIsOnOwningThread();
    6926           0 :   MOZ_ASSERT(aQuota);
    6927             : 
    6928           0 :   if (NS_WARN_IF(!QuotaUsageRequestBase::Init(aQuota))) {
    6929           0 :     return false;
    6930             :   }
    6931             : 
    6932           0 :   mNeedsMainThreadInit = true;
    6933             : 
    6934           0 :   return true;
    6935             : }
    6936             : 
    6937             : nsresult
    6938           0 : GetOriginUsageOp::DoInitOnMainThread()
    6939             : {
    6940           0 :   MOZ_ASSERT(NS_IsMainThread());
    6941           0 :   MOZ_ASSERT(GetState() == State_Initializing);
    6942           0 :   MOZ_ASSERT(mNeedsMainThreadInit);
    6943             : 
    6944           0 :   const PrincipalInfo& principalInfo = mParams.principalInfo();
    6945             : 
    6946             :   nsresult rv;
    6947             :   nsCOMPtr<nsIPrincipal> principal =
    6948           0 :     PrincipalInfoToPrincipal(principalInfo, &rv);
    6949           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    6950           0 :     return rv;
    6951             :   }
    6952             : 
    6953             :   // Figure out which origin we're dealing with.
    6954           0 :   nsCString origin;
    6955           0 :   rv = QuotaManager::GetInfoFromPrincipal(principal, &mSuffix, &mGroup,
    6956             :                                           &origin);
    6957           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    6958           0 :     return rv;
    6959             :   }
    6960             : 
    6961           0 :   mOriginScope.SetFromOrigin(origin);
    6962             : 
    6963           0 :   return NS_OK;
    6964             : }
    6965             : 
    6966             : nsresult
    6967           0 : GetOriginUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager)
    6968             : {
    6969           0 :   AssertIsOnIOThread();
    6970           0 :   MOZ_ASSERT(mUsageInfo.TotalUsage() == 0);
    6971             : 
    6972           0 :   AUTO_PROFILER_LABEL("GetOriginUsageOp::DoDirectoryWork", OTHER);
    6973             : 
    6974             :   nsresult rv;
    6975             : 
    6976           0 :   if (mGetGroupUsage) {
    6977           0 :     nsCOMPtr<nsIFile> directory;
    6978             : 
    6979             :     // Ensure origin is initialized first. It will initialize all origins for
    6980             :     // temporary storage including origins belonging to our group.
    6981           0 :     rv = aQuotaManager->EnsureOriginIsInitialized(PERSISTENCE_TYPE_TEMPORARY,
    6982             :                                                   mSuffix, mGroup,
    6983             :                                                   mOriginScope.GetOrigin(),
    6984           0 :                                                   getter_AddRefs(directory));
    6985           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    6986           0 :       return rv;
    6987             :     }
    6988             : 
    6989             :     // Get cached usage and limit (the method doesn't have to stat any files).
    6990           0 :     aQuotaManager->GetGroupUsageAndLimit(mGroup, &mUsageInfo);
    6991             : 
    6992           0 :     return NS_OK;
    6993             :   }
    6994             : 
    6995             :   // Add all the persistent/temporary/default storage files we care about.
    6996           0 :   for (const PersistenceType type : kAllPersistenceTypes) {
    6997           0 :     UsageInfo usageInfo;
    6998           0 :     rv = GetUsageForOrigin(aQuotaManager,
    6999             :                            type,
    7000             :                            mGroup,
    7001             :                            mOriginScope.GetOrigin(),
    7002           0 :                            &usageInfo);
    7003           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    7004           0 :       return rv;
    7005             :     }
    7006             : 
    7007           0 :     mUsageInfo.Append(usageInfo);
    7008             :   }
    7009             : 
    7010           0 :   return NS_OK;
    7011             : }
    7012             : 
    7013             : void
    7014           0 : GetOriginUsageOp::GetResponse(UsageRequestResponse& aResponse)
    7015             : {
    7016           0 :   AssertIsOnOwningThread();
    7017             : 
    7018           0 :   OriginUsageResponse usageResponse;
    7019             : 
    7020             :   // We'll get the group usage when mGetGroupUsage is true and get the
    7021             :   // origin usage when mGetGroupUsage is false.
    7022           0 :   usageResponse.usage() = mUsageInfo.TotalUsage();
    7023             : 
    7024           0 :   if (mGetGroupUsage) {
    7025           0 :     usageResponse.limit() = mUsageInfo.Limit();
    7026             :   } else {
    7027           0 :     usageResponse.fileUsage() = mUsageInfo.FileUsage();
    7028             :   }
    7029             : 
    7030           0 :   aResponse = usageResponse;
    7031           0 : }
    7032             : 
    7033             : bool
    7034           0 : QuotaRequestBase::Init(Quota* aQuota)
    7035             : {
    7036           0 :   AssertIsOnOwningThread();
    7037           0 :   MOZ_ASSERT(aQuota);
    7038             : 
    7039           0 :   mNeedsQuotaManagerInit = true;
    7040             : 
    7041           0 :   return true;
    7042             : }
    7043             : 
    7044             : void
    7045           0 : QuotaRequestBase::SendResults()
    7046             : {
    7047           0 :   AssertIsOnOwningThread();
    7048             : 
    7049           0 :   if (IsActorDestroyed()) {
    7050           0 :     if (NS_SUCCEEDED(mResultCode)) {
    7051           0 :       mResultCode = NS_ERROR_FAILURE;
    7052             :     }
    7053             :   } else {
    7054           0 :     RequestResponse response;
    7055             : 
    7056           0 :     if (NS_SUCCEEDED(mResultCode)) {
    7057           0 :       GetResponse(response);
    7058             :     } else {
    7059           0 :       response = mResultCode;
    7060             :     }
    7061             : 
    7062           0 :     Unused << PQuotaRequestParent::Send__delete__(this, response);
    7063             :   }
    7064           0 : }
    7065             : 
    7066             : void
    7067           0 : QuotaRequestBase::ActorDestroy(ActorDestroyReason aWhy)
    7068             : {
    7069           0 :   AssertIsOnOwningThread();
    7070             : 
    7071           0 :   NoteActorDestroyed();
    7072           0 : }
    7073             : 
    7074             : nsresult
    7075           0 : InitOp::DoDirectoryWork(QuotaManager* aQuotaManager)
    7076             : {
    7077           0 :   AssertIsOnIOThread();
    7078             : 
    7079           0 :   AUTO_PROFILER_LABEL("InitOp::DoDirectoryWork", OTHER);
    7080             : 
    7081           0 :   aQuotaManager->AssertStorageIsInitialized();
    7082             : 
    7083           0 :   return NS_OK;
    7084             : }
    7085             : 
    7086             : void
    7087           0 : InitOp::GetResponse(RequestResponse& aResponse)
    7088             : {
    7089           0 :   AssertIsOnOwningThread();
    7090             : 
    7091           0 :   aResponse = InitResponse();
    7092           0 : }
    7093             : 
    7094           0 : InitOriginOp::InitOriginOp(const RequestParams& aParams)
    7095             :   : QuotaRequestBase(/* aExclusive */ false)
    7096           0 :   , mParams(aParams.get_InitOriginParams())
    7097           0 :   , mCreated(false)
    7098             : {
    7099           0 :   AssertIsOnOwningThread();
    7100           0 :   MOZ_ASSERT(aParams.type() == RequestParams::TInitOriginParams);
    7101           0 : }
    7102             : 
    7103             : bool
    7104           0 : InitOriginOp::Init(Quota* aQuota)
    7105             : {
    7106           0 :   AssertIsOnOwningThread();
    7107           0 :   MOZ_ASSERT(aQuota);
    7108             : 
    7109           0 :   if (NS_WARN_IF(!QuotaRequestBase::Init(aQuota))) {
    7110           0 :     return false;
    7111             :   }
    7112             : 
    7113           0 :   MOZ_ASSERT(mParams.persistenceType() != PERSISTENCE_TYPE_INVALID);
    7114             : 
    7115           0 :   mPersistenceType.SetValue(mParams.persistenceType());
    7116             : 
    7117           0 :   mNeedsMainThreadInit = true;
    7118             : 
    7119           0 :   return true;
    7120             : }
    7121             : 
    7122             : nsresult
    7123           0 : InitOriginOp::DoInitOnMainThread()
    7124             : {
    7125           0 :   MOZ_ASSERT(NS_IsMainThread());
    7126           0 :   MOZ_ASSERT(GetState() == State_Initializing);
    7127           0 :   MOZ_ASSERT(mNeedsMainThreadInit);
    7128             : 
    7129           0 :   const PrincipalInfo& principalInfo = mParams.principalInfo();
    7130             : 
    7131             :   nsresult rv;
    7132             :   nsCOMPtr<nsIPrincipal> principal =
    7133           0 :     PrincipalInfoToPrincipal(principalInfo, &rv);
    7134           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7135           0 :     return rv;
    7136             :   }
    7137             : 
    7138             :   // Figure out which origin we're dealing with.
    7139           0 :   nsCString origin;
    7140           0 :   rv = QuotaManager::GetInfoFromPrincipal(principal, &mSuffix, &mGroup,
    7141             :                                           &origin);
    7142           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7143           0 :     return rv;
    7144             :   }
    7145             : 
    7146           0 :   mOriginScope.SetFromOrigin(origin);
    7147             : 
    7148           0 :   return NS_OK;
    7149             : }
    7150             : 
    7151             : nsresult
    7152           0 : InitOriginOp::DoDirectoryWork(QuotaManager* aQuotaManager)
    7153             : {
    7154           0 :   AssertIsOnIOThread();
    7155           0 :   MOZ_ASSERT(!mPersistenceType.IsNull());
    7156             : 
    7157           0 :   AUTO_PROFILER_LABEL("InitOriginOp::DoDirectoryWork", OTHER);
    7158             : 
    7159           0 :   nsCOMPtr<nsIFile> directory;
    7160             :   bool created;
    7161             :   nsresult rv =
    7162           0 :     aQuotaManager->EnsureOriginIsInitializedInternal(mPersistenceType.Value(),
    7163             :                                                      mSuffix,
    7164             :                                                      mGroup,
    7165             :                                                      mOriginScope.GetOrigin(),
    7166           0 :                                                      getter_AddRefs(directory),
    7167           0 :                                                      &created);
    7168           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7169           0 :     return rv;
    7170             :   }
    7171             : 
    7172           0 :   mCreated = created;
    7173             : 
    7174           0 :   return NS_OK;
    7175             : }
    7176             : 
    7177             : void
    7178           0 : InitOriginOp::GetResponse(RequestResponse& aResponse)
    7179             : {
    7180           0 :   AssertIsOnOwningThread();
    7181             : 
    7182           0 :   InitOriginResponse response;
    7183             : 
    7184           0 :   response.created() = mCreated;
    7185             : 
    7186           0 :   aResponse = response;
    7187           0 : }
    7188             : 
    7189             : void
    7190           0 : ResetOrClearOp::DeleteFiles(QuotaManager* aQuotaManager)
    7191             : {
    7192           0 :   AssertIsOnIOThread();
    7193           0 :   MOZ_ASSERT(aQuotaManager);
    7194             : 
    7195             :   nsresult rv;
    7196             : 
    7197             :   nsCOMPtr<nsIFile> directory =
    7198           0 :     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    7199           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7200           0 :     return;
    7201             :   }
    7202             : 
    7203           0 :   rv = directory->InitWithPath(aQuotaManager->GetStoragePath());
    7204           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7205           0 :     return;
    7206             :   }
    7207             : 
    7208           0 :   rv = directory->Remove(true);
    7209           0 :   if (rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST &&
    7210           0 :       rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
    7211             :     // This should never fail if we've closed all storage connections
    7212             :     // correctly...
    7213           0 :     MOZ_ASSERT(false, "Failed to remove storage directory!");
    7214             :   }
    7215             : 
    7216             :   nsCOMPtr<nsIFile> storageFile =
    7217           0 :     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    7218           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7219           0 :     return;
    7220             :   }
    7221             : 
    7222           0 :   rv = storageFile->InitWithPath(aQuotaManager->GetBasePath());
    7223           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7224           0 :     return;
    7225             :   }
    7226             : 
    7227           0 :   rv = storageFile->Append(NS_LITERAL_STRING(STORAGE_FILE_NAME));
    7228           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7229           0 :     return;
    7230             :   }
    7231             : 
    7232           0 :   rv = storageFile->Remove(true);
    7233           0 :   if (rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST &&
    7234           0 :       rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
    7235             :     // This should never fail if we've closed the storage connection
    7236             :     // correctly...
    7237           0 :     MOZ_ASSERT(false, "Failed to remove storage file!");
    7238             :   }
    7239             : }
    7240             : 
    7241             : nsresult
    7242           0 : ResetOrClearOp::DoDirectoryWork(QuotaManager* aQuotaManager)
    7243             : {
    7244           0 :   AssertIsOnIOThread();
    7245             : 
    7246           0 :   AUTO_PROFILER_LABEL("ResetOrClearOp::DoDirectoryWork", OTHER);
    7247             : 
    7248           0 :   if (mClear) {
    7249           0 :     DeleteFiles(aQuotaManager);
    7250             :   }
    7251             : 
    7252           0 :   aQuotaManager->RemoveQuota();
    7253             : 
    7254           0 :   aQuotaManager->ResetOrClearCompleted();
    7255             : 
    7256           0 :   return NS_OK;
    7257             : }
    7258             : 
    7259             : void
    7260           0 : ResetOrClearOp::GetResponse(RequestResponse& aResponse)
    7261             : {
    7262           0 :   AssertIsOnOwningThread();
    7263           0 :   if (mClear) {
    7264           0 :     aResponse = ClearAllResponse();
    7265             :   } else {
    7266           0 :     aResponse = ResetAllResponse();
    7267             :   }
    7268           0 : }
    7269             : 
    7270             : void
    7271           0 : ClearRequestBase::DeleteFiles(QuotaManager* aQuotaManager,
    7272             :                               PersistenceType aPersistenceType)
    7273             : {
    7274           0 :   AssertIsOnIOThread();
    7275           0 :   MOZ_ASSERT(aQuotaManager);
    7276             : 
    7277             :   nsresult rv;
    7278             : 
    7279             :   nsCOMPtr<nsIFile> directory =
    7280           0 :     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    7281           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7282           0 :     return;
    7283             :   }
    7284             : 
    7285           0 :   rv = directory->InitWithPath(aQuotaManager->GetStoragePath(aPersistenceType));
    7286           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7287           0 :     return;
    7288             :   }
    7289             : 
    7290           0 :   nsCOMPtr<nsISimpleEnumerator> entries;
    7291           0 :   if (NS_WARN_IF(NS_FAILED(
    7292           0 :         directory->GetDirectoryEntries(getter_AddRefs(entries)))) || !entries) {
    7293           0 :     return;
    7294             :   }
    7295             : 
    7296           0 :   OriginScope originScope = mOriginScope.Clone();
    7297           0 :   if (originScope.IsOrigin()) {
    7298           0 :     nsCString originSanitized(originScope.GetOrigin());
    7299           0 :     SanitizeOriginString(originSanitized);
    7300           0 :     originScope.SetOrigin(originSanitized);
    7301           0 :   } else if (originScope.IsPrefix()) {
    7302           0 :     nsCString prefixSanitized(originScope.GetPrefix());
    7303           0 :     SanitizeOriginString(prefixSanitized);
    7304           0 :     originScope.SetPrefix(prefixSanitized);
    7305             :   }
    7306             : 
    7307             :   bool hasMore;
    7308           0 :   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
    7309           0 :     nsCOMPtr<nsISupports> entry;
    7310           0 :     rv = entries->GetNext(getter_AddRefs(entry));
    7311           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    7312           0 :       return;
    7313             :     }
    7314             : 
    7315           0 :     nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
    7316           0 :     MOZ_ASSERT(file);
    7317             : 
    7318             :     bool isDirectory;
    7319           0 :     rv = file->IsDirectory(&isDirectory);
    7320           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    7321           0 :       return;
    7322             :     }
    7323             : 
    7324           0 :     nsString leafName;
    7325           0 :     rv = file->GetLeafName(leafName);
    7326           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    7327           0 :       return;
    7328             :     }
    7329             : 
    7330           0 :     if (!isDirectory) {
    7331             :       // Unknown files during clearing are allowed. Just warn if we find them.
    7332           0 :       if (!IsOSMetadata(leafName)) {
    7333           0 :         UNKNOWN_FILE_WARNING(leafName);
    7334             :       }
    7335           0 :       continue;
    7336             :     }
    7337             : 
    7338             :     // Skip the origin directory if it doesn't match the pattern.
    7339           0 :     if (!originScope.MatchesOrigin(OriginScope::FromOrigin(
    7340           0 :                                      NS_ConvertUTF16toUTF8(leafName)))) {
    7341           0 :       continue;
    7342             :     }
    7343             : 
    7344           0 :     bool persistent = aPersistenceType == PERSISTENCE_TYPE_PERSISTENT;
    7345             : 
    7346             :     int64_t timestamp;
    7347           0 :     nsCString suffix;
    7348           0 :     nsCString group;
    7349           0 :     nsCString origin;
    7350             :     bool persisted;
    7351           0 :     rv = aQuotaManager->GetDirectoryMetadata2WithRestore(file,
    7352             :                                                          persistent,
    7353             :                                                          &timestamp,
    7354             :                                                          &persisted,
    7355             :                                                          suffix,
    7356             :                                                          group,
    7357             :                                                          origin);
    7358           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    7359           0 :       return;
    7360             :     }
    7361             : 
    7362           0 :     for (uint32_t index = 0; index < 10; index++) {
    7363             :       // We can't guarantee that this will always succeed on Windows...
    7364           0 :       if (NS_SUCCEEDED((rv = file->Remove(true)))) {
    7365           0 :         break;
    7366             :       }
    7367             : 
    7368           0 :       NS_WARNING("Failed to remove directory, retrying after a short delay.");
    7369             : 
    7370           0 :       PR_Sleep(PR_MillisecondsToInterval(200));
    7371             :     }
    7372             : 
    7373           0 :     if (NS_FAILED(rv)) {
    7374           0 :       NS_WARNING("Failed to remove directory, giving up!");
    7375             :     }
    7376             : 
    7377           0 :     if (aPersistenceType != PERSISTENCE_TYPE_PERSISTENT) {
    7378           0 :       aQuotaManager->RemoveQuotaForOrigin(aPersistenceType, group, origin);
    7379             :     }
    7380             : 
    7381           0 :     aQuotaManager->OriginClearCompleted(aPersistenceType, origin);
    7382             :   }
    7383             : 
    7384             : }
    7385             : 
    7386             : nsresult
    7387           0 : ClearRequestBase::DoDirectoryWork(QuotaManager* aQuotaManager)
    7388             : {
    7389           0 :   AssertIsOnIOThread();
    7390             : 
    7391           0 :   AUTO_PROFILER_LABEL("ClearRequestBase::DoDirectoryWork", OTHER);
    7392             : 
    7393           0 :   if (mPersistenceType.IsNull()) {
    7394           0 :     for (const PersistenceType type : kAllPersistenceTypes) {
    7395           0 :       DeleteFiles(aQuotaManager, type);
    7396             :     }
    7397             :   } else {
    7398           0 :     DeleteFiles(aQuotaManager, mPersistenceType.Value());
    7399             :   }
    7400             : 
    7401           0 :   return NS_OK;
    7402             : }
    7403             : 
    7404           0 : ClearOriginOp::ClearOriginOp(const RequestParams& aParams)
    7405             :   : ClearRequestBase(/* aExclusive */ true)
    7406           0 :   , mParams(aParams)
    7407             : {
    7408           0 :   MOZ_ASSERT(aParams.type() == RequestParams::TClearOriginParams);
    7409           0 : }
    7410             : 
    7411             : bool
    7412           0 : ClearOriginOp::Init(Quota* aQuota)
    7413             : {
    7414           0 :   AssertIsOnOwningThread();
    7415           0 :   MOZ_ASSERT(aQuota);
    7416             : 
    7417           0 :   if (NS_WARN_IF(!QuotaRequestBase::Init(aQuota))) {
    7418           0 :     return false;
    7419             :   }
    7420             : 
    7421           0 :   if (mParams.persistenceTypeIsExplicit()) {
    7422           0 :     MOZ_ASSERT(mParams.persistenceType() != PERSISTENCE_TYPE_INVALID);
    7423             : 
    7424           0 :     mPersistenceType.SetValue(mParams.persistenceType());
    7425             :   }
    7426             : 
    7427           0 :   mNeedsMainThreadInit = true;
    7428             : 
    7429           0 :   return true;
    7430             : }
    7431             : 
    7432             : nsresult
    7433           0 : ClearOriginOp::DoInitOnMainThread()
    7434             : {
    7435           0 :   MOZ_ASSERT(NS_IsMainThread());
    7436           0 :   MOZ_ASSERT(GetState() == State_Initializing);
    7437           0 :   MOZ_ASSERT(mNeedsMainThreadInit);
    7438             : 
    7439           0 :   const PrincipalInfo& principalInfo = mParams.principalInfo();
    7440             : 
    7441             :   nsresult rv;
    7442             :   nsCOMPtr<nsIPrincipal> principal =
    7443           0 :     PrincipalInfoToPrincipal(principalInfo, &rv);
    7444           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7445           0 :     return rv;
    7446             :   }
    7447             : 
    7448             :   // Figure out which origin we're dealing with.
    7449           0 :   nsCString origin;
    7450           0 :   rv = QuotaManager::GetInfoFromPrincipal(principal, nullptr, nullptr,
    7451             :                                           &origin);
    7452           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7453           0 :     return rv;
    7454             :   }
    7455             : 
    7456           0 :   if (mParams.clearAll()) {
    7457           0 :     mOriginScope.SetFromPrefix(origin);
    7458             :   } else {
    7459           0 :     mOriginScope.SetFromOrigin(origin);
    7460             :   }
    7461             : 
    7462           0 :   return NS_OK;
    7463             : }
    7464             : 
    7465             : void
    7466           0 : ClearOriginOp::GetResponse(RequestResponse& aResponse)
    7467             : {
    7468           0 :   AssertIsOnOwningThread();
    7469             : 
    7470           0 :   aResponse = ClearOriginResponse();
    7471           0 : }
    7472             : 
    7473           0 : ClearDataOp::ClearDataOp(const RequestParams& aParams)
    7474             :   : ClearRequestBase(/* aExclusive */ true)
    7475           0 :   , mParams(aParams)
    7476             : {
    7477           0 :   MOZ_ASSERT(aParams.type() == RequestParams::TClearDataParams);
    7478           0 : }
    7479             : 
    7480             : bool
    7481           0 : ClearDataOp::Init(Quota* aQuota)
    7482             : {
    7483           0 :   AssertIsOnOwningThread();
    7484           0 :   MOZ_ASSERT(aQuota);
    7485             : 
    7486           0 :   if (NS_WARN_IF(!QuotaRequestBase::Init(aQuota))) {
    7487           0 :     return false;
    7488             :   }
    7489             : 
    7490           0 :   mNeedsMainThreadInit = true;
    7491             : 
    7492           0 :   return true;
    7493             : }
    7494             : 
    7495             : nsresult
    7496           0 : ClearDataOp::DoInitOnMainThread()
    7497             : {
    7498           0 :   MOZ_ASSERT(NS_IsMainThread());
    7499           0 :   MOZ_ASSERT(GetState() == State_Initializing);
    7500           0 :   MOZ_ASSERT(mNeedsMainThreadInit);
    7501             : 
    7502           0 :   mOriginScope.SetFromJSONPattern(mParams.pattern());
    7503             : 
    7504           0 :   return NS_OK;
    7505             : }
    7506             : 
    7507             : void
    7508           0 : ClearDataOp::GetResponse(RequestResponse& aResponse)
    7509             : {
    7510           0 :   AssertIsOnOwningThread();
    7511             : 
    7512           0 :   aResponse = ClearDataResponse();
    7513           0 : }
    7514             : 
    7515           0 : PersistRequestBase::PersistRequestBase(const PrincipalInfo& aPrincipalInfo)
    7516             :   : QuotaRequestBase(/* aExclusive */ false)
    7517           0 :   , mPrincipalInfo(aPrincipalInfo)
    7518             : {
    7519           0 :   AssertIsOnOwningThread();
    7520           0 : }
    7521             : 
    7522             : bool
    7523           0 : PersistRequestBase::Init(Quota* aQuota)
    7524             : {
    7525           0 :   AssertIsOnOwningThread();
    7526           0 :   MOZ_ASSERT(aQuota);
    7527             : 
    7528           0 :   if (NS_WARN_IF(!QuotaRequestBase::Init(aQuota))) {
    7529           0 :     return false;
    7530             :   }
    7531             : 
    7532           0 :   mPersistenceType.SetValue(PERSISTENCE_TYPE_DEFAULT);
    7533             : 
    7534           0 :   mNeedsMainThreadInit = true;
    7535             : 
    7536           0 :   return true;
    7537             : }
    7538             : 
    7539             : nsresult
    7540           0 : PersistRequestBase::DoInitOnMainThread()
    7541             : {
    7542           0 :   MOZ_ASSERT(NS_IsMainThread());
    7543           0 :   MOZ_ASSERT(GetState() == State_Initializing);
    7544           0 :   MOZ_ASSERT(mNeedsMainThreadInit);
    7545             : 
    7546             :   nsresult rv;
    7547             :   nsCOMPtr<nsIPrincipal> principal =
    7548           0 :     PrincipalInfoToPrincipal(mPrincipalInfo, &rv);
    7549           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7550           0 :     return rv;
    7551             :   }
    7552             : 
    7553             :   // Figure out which origin we're dealing with.
    7554           0 :   nsCString origin;
    7555           0 :   rv = QuotaManager::GetInfoFromPrincipal(principal, &mSuffix, &mGroup,
    7556             :                                           &origin);
    7557           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7558           0 :     return rv;
    7559             :   }
    7560             : 
    7561           0 :   mOriginScope.SetFromOrigin(origin);
    7562             : 
    7563           0 :   return NS_OK;
    7564             : }
    7565             : 
    7566           0 : PersistedOp::PersistedOp(const RequestParams& aParams)
    7567           0 :   : PersistRequestBase(aParams.get_PersistedParams().principalInfo())
    7568           0 :   , mPersisted(false)
    7569             : {
    7570           0 :   MOZ_ASSERT(aParams.type() == RequestParams::TPersistedParams);
    7571           0 : }
    7572             : 
    7573             : nsresult
    7574           0 : PersistedOp::DoDirectoryWork(QuotaManager* aQuotaManager)
    7575             : {
    7576           0 :   AssertIsOnIOThread();
    7577           0 :   MOZ_ASSERT(!mPersistenceType.IsNull());
    7578           0 :   MOZ_ASSERT(mPersistenceType.Value() == PERSISTENCE_TYPE_DEFAULT);
    7579           0 :   MOZ_ASSERT(mOriginScope.IsOrigin());
    7580             : 
    7581           0 :   AUTO_PROFILER_LABEL("PersistedOp::DoDirectoryWork", OTHER);
    7582             : 
    7583             :   Nullable<bool> persisted =
    7584           0 :     aQuotaManager->OriginPersisted(mGroup, mOriginScope.GetOrigin());
    7585             : 
    7586           0 :   if (!persisted.IsNull()) {
    7587           0 :     mPersisted = persisted.Value();
    7588           0 :     return NS_OK;
    7589             :   }
    7590             : 
    7591             :   // If we get here, it means the origin hasn't been initialized yet.
    7592             :   // Try to get the persisted flag from directory metadata on disk.
    7593             : 
    7594           0 :   nsCOMPtr<nsIFile> directory;
    7595           0 :   nsresult rv = aQuotaManager->GetDirectoryForOrigin(mPersistenceType.Value(),
    7596             :                                                      mOriginScope.GetOrigin(),
    7597           0 :                                                      getter_AddRefs(directory));
    7598           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7599           0 :     return rv;
    7600             :   }
    7601             : 
    7602             :   bool exists;
    7603           0 :   rv = directory->Exists(&exists);
    7604           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7605           0 :     return rv;
    7606             :   }
    7607             : 
    7608           0 :   if (exists) {
    7609             :     // Get the persisted flag.
    7610             :     bool persisted;
    7611             :     rv =
    7612           0 :       aQuotaManager->GetDirectoryMetadata2WithRestore(directory,
    7613             :                                                       /* aPersistent */ false,
    7614             :                                                       /* aTimestamp */ nullptr,
    7615           0 :                                                       &persisted);
    7616           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    7617           0 :       return rv;
    7618             :     }
    7619             : 
    7620           0 :     mPersisted = persisted;
    7621             :   } else {
    7622             :     // The directory has not been created yet.
    7623           0 :     mPersisted = false;
    7624             :   }
    7625             : 
    7626           0 :   return NS_OK;
    7627             : }
    7628             : 
    7629             : void
    7630           0 : PersistedOp::GetResponse(RequestResponse& aResponse)
    7631             : {
    7632           0 :   AssertIsOnOwningThread();
    7633             : 
    7634           0 :   PersistedResponse persistedResponse;
    7635           0 :   persistedResponse.persisted() = mPersisted;
    7636             : 
    7637           0 :   aResponse = persistedResponse;
    7638           0 : }
    7639             : 
    7640           0 : PersistOp::PersistOp(const RequestParams& aParams)
    7641           0 :   : PersistRequestBase(aParams.get_PersistParams().principalInfo())
    7642             : {
    7643           0 :   MOZ_ASSERT(aParams.type() == RequestParams::TPersistParams);
    7644           0 : }
    7645             : 
    7646             : nsresult
    7647           0 : PersistOp::DoDirectoryWork(QuotaManager* aQuotaManager)
    7648             : {
    7649           0 :   AssertIsOnIOThread();
    7650           0 :   MOZ_ASSERT(!mPersistenceType.IsNull());
    7651           0 :   MOZ_ASSERT(mPersistenceType.Value() == PERSISTENCE_TYPE_DEFAULT);
    7652           0 :   MOZ_ASSERT(mOriginScope.IsOrigin());
    7653             : 
    7654           0 :   AUTO_PROFILER_LABEL("PersistOp::DoDirectoryWork", OTHER);
    7655             : 
    7656             :   // Update directory metadata on disk first. Then, create/update the originInfo
    7657             :   // if needed.
    7658           0 :   nsCOMPtr<nsIFile> directory;
    7659           0 :   nsresult rv = aQuotaManager->GetDirectoryForOrigin(mPersistenceType.Value(),
    7660             :                                                      mOriginScope.GetOrigin(),
    7661           0 :                                                      getter_AddRefs(directory));
    7662           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7663           0 :     return rv;
    7664             :   }
    7665             : 
    7666             :   bool created;
    7667           0 :   rv = EnsureOriginDirectory(directory, &created);
    7668           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7669           0 :     return rv;
    7670             :   }
    7671             : 
    7672           0 :   if (created) {
    7673             :     int64_t timestamp;
    7674           0 :     rv = CreateDirectoryMetadataFiles(directory,
    7675             :                                       /* aPersisted */ true,
    7676             :                                       mSuffix,
    7677             :                                       mGroup,
    7678             :                                       mOriginScope.GetOrigin(),
    7679           0 :                                       &timestamp);
    7680           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    7681           0 :       return rv;
    7682             :     }
    7683             : 
    7684             :     // Directory metadata has been successfully created.
    7685             :     // Create OriginInfo too if temporary storage was already initialized.
    7686           0 :     if (aQuotaManager->IsTemporaryStorageInitialized()) {
    7687           0 :       aQuotaManager->InitQuotaForOrigin(mPersistenceType.Value(),
    7688             :                                         mGroup,
    7689             :                                         mOriginScope.GetOrigin(),
    7690             :                                         /* aUsageBytes */ 0,
    7691             :                                         timestamp,
    7692           0 :                                         /* aPersisted */ true);
    7693             :     }
    7694             :   } else {
    7695             :     // Get the persisted flag (restore the metadata file if necessary).
    7696             :     bool persisted;
    7697             :     rv =
    7698           0 :       aQuotaManager->GetDirectoryMetadata2WithRestore(directory,
    7699             :                                                       /* aPersistent */ false,
    7700             :                                                       /* aTimestamp */ nullptr,
    7701           0 :                                                       &persisted);
    7702           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    7703           0 :       return rv;
    7704             :     }
    7705             : 
    7706           0 :     if (!persisted) {
    7707           0 :       nsCOMPtr<nsIFile> file;
    7708           0 :       nsresult rv = directory->Clone(getter_AddRefs(file));
    7709           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    7710           0 :         return rv;
    7711             :       }
    7712             : 
    7713           0 :       rv = file->Append(NS_LITERAL_STRING(METADATA_V2_FILE_NAME));
    7714           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    7715           0 :         return rv;
    7716             :       }
    7717             : 
    7718           0 :       nsCOMPtr<nsIBinaryOutputStream> stream;
    7719           0 :       rv = GetBinaryOutputStream(file, kUpdateFileFlag, getter_AddRefs(stream));
    7720           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    7721           0 :         return rv;
    7722             :       }
    7723             : 
    7724           0 :       MOZ_ASSERT(stream);
    7725             : 
    7726             :       // Update origin access time while we are here.
    7727           0 :       rv = stream->Write64(PR_Now());
    7728           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    7729           0 :         return rv;
    7730             :       }
    7731             : 
    7732             :       // Set the persisted flag to true.
    7733           0 :       rv = stream->WriteBoolean(true);
    7734           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    7735           0 :         return rv;
    7736             :       }
    7737             :     }
    7738             : 
    7739             :     // Directory metadata has been successfully updated.
    7740             :     // Update OriginInfo too if temporary storage was already initialized.
    7741           0 :     if (aQuotaManager->IsTemporaryStorageInitialized()) {
    7742           0 :       aQuotaManager->PersistOrigin(mGroup, mOriginScope.GetOrigin());
    7743             :     }
    7744             :   }
    7745             : 
    7746           0 :   return NS_OK;
    7747             : }
    7748             : 
    7749             : void
    7750           0 : PersistOp::GetResponse(RequestResponse& aResponse)
    7751             : {
    7752           0 :   AssertIsOnOwningThread();
    7753             : 
    7754           0 :   aResponse = PersistResponse();
    7755           0 : }
    7756             : 
    7757             : nsresult
    7758           0 : StorageDirectoryHelper::GetDirectoryMetadata(nsIFile* aDirectory,
    7759             :                                              int64_t& aTimestamp,
    7760             :                                              nsACString& aGroup,
    7761             :                                              nsACString& aOrigin,
    7762             :                                              Nullable<bool>& aIsApp)
    7763             : {
    7764           0 :   AssertIsOnIOThread();
    7765           0 :   MOZ_ASSERT(aDirectory);
    7766             : 
    7767           0 :   nsCOMPtr<nsIBinaryInputStream> binaryStream;
    7768           0 :   nsresult rv = GetBinaryInputStream(aDirectory,
    7769           0 :                                      NS_LITERAL_STRING(METADATA_FILE_NAME),
    7770           0 :                                      getter_AddRefs(binaryStream));
    7771           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7772           0 :     return rv;
    7773             :   }
    7774             : 
    7775             :   uint64_t timestamp;
    7776           0 :   rv = binaryStream->Read64(&timestamp);
    7777           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7778           0 :     return rv;
    7779             :   }
    7780             : 
    7781           0 :   nsCString group;
    7782           0 :   rv = binaryStream->ReadCString(group);
    7783           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7784           0 :     return rv;
    7785             :   }
    7786             : 
    7787           0 :   nsCString origin;
    7788           0 :   rv = binaryStream->ReadCString(origin);
    7789           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7790           0 :     return rv;
    7791             :   }
    7792             : 
    7793           0 :   Nullable<bool> isApp;
    7794             :   bool value;
    7795           0 :   if (NS_SUCCEEDED(binaryStream->ReadBoolean(&value))) {
    7796           0 :     isApp.SetValue(value);
    7797             :   }
    7798             : 
    7799           0 :   aTimestamp = timestamp;
    7800           0 :   aGroup = group;
    7801           0 :   aOrigin = origin;
    7802           0 :   aIsApp = Move(isApp);
    7803           0 :   return NS_OK;
    7804             : }
    7805             : 
    7806             : nsresult
    7807           0 : StorageDirectoryHelper::GetDirectoryMetadata2(nsIFile* aDirectory,
    7808             :                                               int64_t& aTimestamp,
    7809             :                                               nsACString& aSuffix,
    7810             :                                               nsACString& aGroup,
    7811             :                                               nsACString& aOrigin,
    7812             :                                               bool& aIsApp)
    7813             : {
    7814           0 :   AssertIsOnIOThread();
    7815           0 :   MOZ_ASSERT(aDirectory);
    7816             : 
    7817           0 :   nsCOMPtr<nsIBinaryInputStream> binaryStream;
    7818           0 :   nsresult rv = GetBinaryInputStream(aDirectory,
    7819           0 :                                      NS_LITERAL_STRING(METADATA_V2_FILE_NAME),
    7820           0 :                                      getter_AddRefs(binaryStream));
    7821           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7822           0 :     return rv;
    7823             :   }
    7824             : 
    7825             :   uint64_t timestamp;
    7826           0 :   rv = binaryStream->Read64(&timestamp);
    7827           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7828           0 :     return rv;
    7829             :   }
    7830             : 
    7831             :   bool persisted;
    7832           0 :   rv = binaryStream->ReadBoolean(&persisted);
    7833           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7834           0 :     return rv;
    7835             :   }
    7836             : 
    7837             :   uint32_t reservedData1;
    7838           0 :   rv = binaryStream->Read32(&reservedData1);
    7839           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7840           0 :     return rv;
    7841             :   }
    7842             : 
    7843             :   uint32_t reservedData2;
    7844           0 :   rv = binaryStream->Read32(&reservedData2);
    7845           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7846           0 :     return rv;
    7847             :   }
    7848             : 
    7849           0 :   nsCString suffix;
    7850           0 :   rv = binaryStream->ReadCString(suffix);
    7851           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7852           0 :     return rv;
    7853             :   }
    7854             : 
    7855           0 :   nsCString group;
    7856           0 :   rv = binaryStream->ReadCString(group);
    7857           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7858           0 :     return rv;
    7859             :   }
    7860             : 
    7861           0 :   nsCString origin;
    7862           0 :   rv = binaryStream->ReadCString(origin);
    7863           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7864           0 :     return rv;
    7865             :   }
    7866             : 
    7867             :   bool isApp;
    7868           0 :   rv = binaryStream->ReadBoolean(&isApp);
    7869           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7870           0 :     return rv;
    7871             :   }
    7872             : 
    7873           0 :   aTimestamp = timestamp;
    7874           0 :   aSuffix = suffix;
    7875           0 :   aGroup = group;
    7876           0 :   aOrigin = origin;
    7877           0 :   aIsApp = isApp;
    7878           0 :   return NS_OK;
    7879             : }
    7880             : 
    7881             : nsresult
    7882           0 : StorageDirectoryHelper::RemoveObsoleteOrigin(const OriginProps& aOriginProps)
    7883             : {
    7884           0 :   AssertIsOnIOThread();
    7885           0 :   MOZ_ASSERT(aOriginProps.mDirectory);
    7886             : 
    7887           0 :   QM_WARNING("Deleting obsolete %s directory that is no longer a legal "
    7888             :              "origin!", NS_ConvertUTF16toUTF8(aOriginProps.mLeafName).get());
    7889             : 
    7890           0 :   nsresult rv = aOriginProps.mDirectory->Remove(/* recursive */ true);
    7891           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7892           0 :     return rv;
    7893             :   }
    7894             : 
    7895           0 :   return NS_OK;
    7896             : }
    7897             : 
    7898             : nsresult
    7899           0 : StorageDirectoryHelper::ProcessOriginDirectories()
    7900             : {
    7901           0 :   AssertIsOnIOThread();
    7902           0 :   MOZ_ASSERT(!mOriginProps.IsEmpty());
    7903             : 
    7904           0 :   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
    7905             : 
    7906             :   {
    7907           0 :     mozilla::MutexAutoLock autolock(mMutex);
    7908           0 :     while (mWaiting) {
    7909           0 :       mCondVar.Wait();
    7910             :     }
    7911             :   }
    7912             : 
    7913           0 :   if (NS_WARN_IF(NS_FAILED(mMainThreadResultCode))) {
    7914           0 :     return mMainThreadResultCode;
    7915             :   }
    7916             : 
    7917             :   // Verify that the bounce to the main thread didn't start the shutdown
    7918             :   // sequence.
    7919           0 :   if (NS_WARN_IF(QuotaManager::IsShuttingDown())) {
    7920           0 :     return NS_ERROR_FAILURE;
    7921             :   }
    7922             : 
    7923             :   nsresult rv;
    7924             : 
    7925             :   // Don't try to upgrade obsolete origins, remove them right after we detect
    7926             :   // them.
    7927           0 :   for (auto& originProps : mOriginProps) {
    7928           0 :     if (originProps.mType == OriginProps::eObsolete) {
    7929           0 :       MOZ_ASSERT(originProps.mSuffix.IsEmpty());
    7930           0 :       MOZ_ASSERT(originProps.mGroup.IsEmpty());
    7931           0 :       MOZ_ASSERT(originProps.mOrigin.IsEmpty());
    7932             : 
    7933           0 :       rv = RemoveObsoleteOrigin(originProps);
    7934             :     } else {
    7935           0 :       MOZ_ASSERT(!originProps.mGroup.IsEmpty());
    7936           0 :       MOZ_ASSERT(!originProps.mOrigin.IsEmpty());
    7937             : 
    7938           0 :       rv = ProcessOriginDirectory(originProps);
    7939             :     }
    7940           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    7941           0 :       return rv;
    7942             :     }
    7943             :   }
    7944             : 
    7945           0 :   return NS_OK;
    7946             : }
    7947             : 
    7948             : nsresult
    7949           0 : StorageDirectoryHelper::RunOnMainThread()
    7950             : {
    7951           0 :   MOZ_ASSERT(NS_IsMainThread());
    7952           0 :   MOZ_ASSERT(!mOriginProps.IsEmpty());
    7953             : 
    7954             :   nsresult rv;
    7955             : 
    7956             :   nsCOMPtr<nsIScriptSecurityManager> secMan =
    7957           0 :     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
    7958           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7959           0 :     return rv;
    7960             :   }
    7961             : 
    7962           0 :   for (uint32_t count = mOriginProps.Length(), index = 0;
    7963           0 :        index < count;
    7964             :        index++) {
    7965           0 :     OriginProps& originProps = mOriginProps[index];
    7966             : 
    7967           0 :     switch (originProps.mType) {
    7968             :       case OriginProps::eChrome: {
    7969           0 :         QuotaManager::GetInfoForChrome(&originProps.mSuffix,
    7970             :                                        &originProps.mGroup,
    7971           0 :                                        &originProps.mOrigin);
    7972           0 :         break;
    7973             :       }
    7974             : 
    7975             :       case OriginProps::eContent: {
    7976           0 :         nsCOMPtr<nsIURI> uri;
    7977           0 :         rv = NS_NewURI(getter_AddRefs(uri), originProps.mSpec);
    7978           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    7979           0 :           return rv;
    7980             :         }
    7981             : 
    7982             :         nsCOMPtr<nsIPrincipal> principal =
    7983           0 :           BasePrincipal::CreateCodebasePrincipal(uri, originProps.mAttrs);
    7984           0 :         if (NS_WARN_IF(!principal)) {
    7985           0 :           return NS_ERROR_FAILURE;
    7986             :         }
    7987             : 
    7988           0 :         rv = QuotaManager::GetInfoFromPrincipal(principal,
    7989             :                                                 &originProps.mSuffix,
    7990             :                                                 &originProps.mGroup,
    7991             :                                                 &originProps.mOrigin);
    7992           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    7993           0 :           return rv;
    7994             :         }
    7995             : 
    7996           0 :         break;
    7997             :       }
    7998             : 
    7999             :       case OriginProps::eObsolete: {
    8000             :         // There's no way to get info for obsolete origins.
    8001           0 :         break;
    8002             :       }
    8003             : 
    8004             :       default:
    8005           0 :         MOZ_CRASH("Bad type!");
    8006             :     }
    8007             :   }
    8008             : 
    8009           0 :   return NS_OK;
    8010             : }
    8011             : 
    8012             : NS_IMETHODIMP
    8013           0 : StorageDirectoryHelper::Run()
    8014             : {
    8015           0 :   MOZ_ASSERT(NS_IsMainThread());
    8016             : 
    8017           0 :   nsresult rv = RunOnMainThread();
    8018           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8019           0 :     mMainThreadResultCode = rv;
    8020             :   }
    8021             : 
    8022           0 :   MutexAutoLock lock(mMutex);
    8023           0 :   MOZ_ASSERT(mWaiting);
    8024             : 
    8025           0 :   mWaiting = false;
    8026           0 :   mCondVar.Notify();
    8027             : 
    8028           0 :   return NS_OK;
    8029             : }
    8030             : 
    8031             : nsresult
    8032           0 : StorageDirectoryHelper::
    8033             : OriginProps::Init(nsIFile* aDirectory)
    8034             : {
    8035           0 :   AssertIsOnIOThread();
    8036           0 :   MOZ_ASSERT(aDirectory);
    8037             : 
    8038           0 :   nsString leafName;
    8039           0 :   nsresult rv = aDirectory->GetLeafName(leafName);
    8040           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8041           0 :     return rv;
    8042             :   }
    8043             : 
    8044           0 :   if (leafName.EqualsLiteral(kChromeOrigin)) {
    8045           0 :     mDirectory = aDirectory;
    8046           0 :     mLeafName = leafName;
    8047           0 :     mSpec = kChromeOrigin;
    8048           0 :     mType = eChrome;
    8049             :   } else {
    8050           0 :     nsCString spec;
    8051           0 :     OriginAttributes attrs;
    8052             :     OriginParser::ResultType result =
    8053           0 :       OriginParser::ParseOrigin(NS_ConvertUTF16toUTF8(leafName), spec, &attrs);
    8054           0 :     if (NS_WARN_IF(result == OriginParser::InvalidOrigin)) {
    8055           0 :       return NS_ERROR_FAILURE;
    8056             :     }
    8057             : 
    8058           0 :     mDirectory = aDirectory;
    8059           0 :     mLeafName = leafName;
    8060           0 :     mSpec = spec;
    8061           0 :     mAttrs = attrs;
    8062           0 :     mType = result == OriginParser::ObsoleteOrigin ? eObsolete : eContent;
    8063             :   }
    8064             : 
    8065           0 :   return NS_OK;
    8066             : }
    8067             : 
    8068             : // static
    8069             : auto
    8070           0 : OriginParser::ParseOrigin(const nsACString& aOrigin,
    8071             :                           nsCString& aSpec,
    8072             :                           OriginAttributes* aAttrs) -> ResultType
    8073             : {
    8074           0 :   MOZ_ASSERT(!aOrigin.IsEmpty());
    8075           0 :   MOZ_ASSERT(aAttrs);
    8076             : 
    8077           0 :   OriginAttributes originAttributes;
    8078             : 
    8079           0 :   nsCString originNoSuffix;
    8080           0 :   bool ok = originAttributes.PopulateFromOrigin(aOrigin, originNoSuffix);
    8081           0 :   if (!ok) {
    8082           0 :     return InvalidOrigin;
    8083             :   }
    8084             : 
    8085           0 :   OriginParser parser(originNoSuffix, originAttributes);
    8086           0 :   return parser.Parse(aSpec, aAttrs);
    8087             : }
    8088             : 
    8089             : auto
    8090           0 : OriginParser::Parse(nsACString& aSpec, OriginAttributes* aAttrs) -> ResultType
    8091             : {
    8092           0 :   MOZ_ASSERT(aAttrs);
    8093             : 
    8094           0 :   while (mTokenizer.hasMoreTokens()) {
    8095           0 :     const nsDependentCSubstring& token = mTokenizer.nextToken();
    8096             : 
    8097           0 :     HandleToken(token);
    8098             : 
    8099           0 :     if (mError) {
    8100           0 :       break;
    8101             :     }
    8102             : 
    8103           0 :     if (!mHandledTokens.IsEmpty()) {
    8104           0 :       mHandledTokens.Append(NS_LITERAL_CSTRING(", "));
    8105             :     }
    8106           0 :     mHandledTokens.Append('\'');
    8107           0 :     mHandledTokens.Append(token);
    8108           0 :     mHandledTokens.Append('\'');
    8109             :   }
    8110             : 
    8111           0 :   if (!mError && mTokenizer.separatorAfterCurrentToken()) {
    8112           0 :     HandleTrailingSeparator();
    8113             :   }
    8114             : 
    8115           0 :   if (mError) {
    8116           0 :     QM_WARNING("Origin '%s' failed to parse, handled tokens: %s", mOrigin.get(),
    8117             :                mHandledTokens.get());
    8118             : 
    8119           0 :     return InvalidOrigin;
    8120             :   }
    8121             : 
    8122           0 :   MOZ_ASSERT(mState == eComplete || mState == eHandledTrailingSeparator);
    8123             : 
    8124           0 :   if (mAppId == kNoAppId) {
    8125           0 :     *aAttrs = mOriginAttributes;
    8126             :   } else {
    8127           0 :     MOZ_ASSERT(mOriginAttributes.mAppId == kNoAppId);
    8128             : 
    8129           0 :     *aAttrs = OriginAttributes(mAppId, mInIsolatedMozBrowser);
    8130             :   }
    8131             : 
    8132           0 :   nsAutoCString spec(mScheme);
    8133             : 
    8134           0 :   if (mSchemeType == eFile) {
    8135           0 :     spec.AppendLiteral("://");
    8136             : 
    8137           0 :     for (uint32_t count = mPathnameComponents.Length(), index = 0;
    8138           0 :          index < count;
    8139             :          index++) {
    8140           0 :       spec.Append('/');
    8141           0 :       spec.Append(mPathnameComponents[index]);
    8142             :     }
    8143             : 
    8144           0 :     aSpec = spec;
    8145             : 
    8146           0 :     return ValidOrigin;
    8147             :   }
    8148             : 
    8149           0 :   if (mSchemeType == eAbout) {
    8150           0 :     spec.Append(':');
    8151             :   } else {
    8152           0 :     spec.AppendLiteral("://");
    8153             :   }
    8154             : 
    8155           0 :   spec.Append(mHost);
    8156             : 
    8157           0 :   if (!mPort.IsNull()) {
    8158           0 :     spec.Append(':');
    8159           0 :     spec.AppendInt(mPort.Value());
    8160             :   }
    8161             : 
    8162           0 :   aSpec = spec;
    8163             : 
    8164           0 :   return mScheme.EqualsLiteral("app") ? ObsoleteOrigin : ValidOrigin;
    8165             : }
    8166             : 
    8167             : void
    8168           0 : OriginParser::HandleScheme(const nsDependentCSubstring& aToken)
    8169             : {
    8170           0 :   MOZ_ASSERT(!aToken.IsEmpty());
    8171           0 :   MOZ_ASSERT(mState == eExpectingAppIdOrScheme || mState == eExpectingScheme);
    8172             : 
    8173           0 :   bool isAbout = false;
    8174           0 :   bool isFile = false;
    8175           0 :   if (aToken.EqualsLiteral("http") ||
    8176           0 :       aToken.EqualsLiteral("https") ||
    8177           0 :       (isAbout = aToken.EqualsLiteral("about") ||
    8178           0 :                  aToken.EqualsLiteral("moz-safe-about")) ||
    8179           0 :       aToken.EqualsLiteral("indexeddb") ||
    8180           0 :       (isFile = aToken.EqualsLiteral("file")) ||
    8181           0 :       aToken.EqualsLiteral("app") ||
    8182           0 :       aToken.EqualsLiteral("resource") ||
    8183           0 :       aToken.EqualsLiteral("moz-extension")) {
    8184           0 :     mScheme = aToken;
    8185             : 
    8186           0 :     if (isAbout) {
    8187           0 :       mSchemeType = eAbout;
    8188           0 :       mState = eExpectingHost;
    8189             :     } else {
    8190           0 :       if (isFile) {
    8191           0 :         mSchemeType = eFile;
    8192             :       }
    8193           0 :       mState = eExpectingEmptyToken1;
    8194             :     }
    8195             : 
    8196           0 :     return;
    8197             :   }
    8198             : 
    8199           0 :   QM_WARNING("'%s' is not a valid scheme!", nsCString(aToken).get());
    8200             : 
    8201           0 :   mError = true;
    8202             : }
    8203             : 
    8204             : void
    8205           0 : OriginParser::HandlePathnameComponent(const nsDependentCSubstring& aToken)
    8206             : {
    8207           0 :   MOZ_ASSERT(!aToken.IsEmpty());
    8208           0 :   MOZ_ASSERT(mState == eExpectingEmptyTokenOrDriveLetterOrPathnameComponent ||
    8209             :              mState == eExpectingEmptyTokenOrPathnameComponent);
    8210           0 :   MOZ_ASSERT(mSchemeType == eFile);
    8211             : 
    8212           0 :   mPathnameComponents.AppendElement(aToken);
    8213             : 
    8214           0 :   mState = mTokenizer.hasMoreTokens() ? eExpectingEmptyTokenOrPathnameComponent
    8215             :                                       : eComplete;
    8216           0 : }
    8217             : 
    8218             : void
    8219           0 : OriginParser::HandleToken(const nsDependentCSubstring& aToken)
    8220             : {
    8221           0 :   switch (mState) {
    8222             :     case eExpectingAppIdOrScheme: {
    8223           0 :       if (aToken.IsEmpty()) {
    8224           0 :         QM_WARNING("Expected an app id or scheme (not an empty string)!");
    8225             : 
    8226           0 :         mError = true;
    8227           0 :         return;
    8228             :       }
    8229             : 
    8230           0 :       if (NS_IsAsciiDigit(aToken.First())) {
    8231             :         // nsDependentCSubstring doesn't provice ToInteger()
    8232           0 :         nsCString token(aToken);
    8233             : 
    8234             :         nsresult rv;
    8235           0 :         uint32_t appId = token.ToInteger(&rv);
    8236           0 :         if (NS_SUCCEEDED(rv)) {
    8237           0 :           mAppId = appId;
    8238           0 :           mState = eExpectingInMozBrowser;
    8239           0 :           return;
    8240             :         }
    8241             :       }
    8242             : 
    8243           0 :       HandleScheme(aToken);
    8244             : 
    8245           0 :       return;
    8246             :     }
    8247             : 
    8248             :     case eExpectingInMozBrowser: {
    8249           0 :       if (aToken.Length() != 1) {
    8250           0 :         QM_WARNING("'%d' is not a valid length for the inMozBrowser flag!",
    8251             :                    aToken.Length());
    8252             : 
    8253           0 :         mError = true;
    8254           0 :         return;
    8255             :       }
    8256             : 
    8257           0 :       if (aToken.First() == 't') {
    8258           0 :         mInIsolatedMozBrowser = true;
    8259           0 :       } else if (aToken.First() == 'f') {
    8260           0 :         mInIsolatedMozBrowser = false;
    8261             :       } else {
    8262           0 :         QM_WARNING("'%s' is not a valid value for the inMozBrowser flag!",
    8263             :                    nsCString(aToken).get());
    8264             : 
    8265           0 :         mError = true;
    8266           0 :         return;
    8267             :       }
    8268             : 
    8269           0 :       mState = eExpectingScheme;
    8270             : 
    8271           0 :       return;
    8272             :     }
    8273             : 
    8274             :     case eExpectingScheme: {
    8275           0 :       if (aToken.IsEmpty()) {
    8276           0 :         QM_WARNING("Expected a scheme (not an empty string)!");
    8277             : 
    8278           0 :         mError = true;
    8279           0 :         return;
    8280             :       }
    8281             : 
    8282           0 :       HandleScheme(aToken);
    8283             : 
    8284           0 :       return;
    8285             :     }
    8286             : 
    8287             :     case eExpectingEmptyToken1: {
    8288           0 :       if (!aToken.IsEmpty()) {
    8289           0 :         QM_WARNING("Expected the first empty token!");
    8290             : 
    8291           0 :         mError = true;
    8292           0 :         return;
    8293             :       }
    8294             : 
    8295           0 :       mState = eExpectingEmptyToken2;
    8296             : 
    8297           0 :       return;
    8298             :     }
    8299             : 
    8300             :     case eExpectingEmptyToken2: {
    8301           0 :       if (!aToken.IsEmpty()) {
    8302           0 :         QM_WARNING("Expected the second empty token!");
    8303             : 
    8304           0 :         mError = true;
    8305           0 :         return;
    8306             :       }
    8307             : 
    8308           0 :       if (mSchemeType == eFile) {
    8309           0 :         mState = eExpectingEmptyToken3;
    8310             :       } else {
    8311           0 :         mState = eExpectingHost;
    8312             :       }
    8313             : 
    8314           0 :       return;
    8315             :     }
    8316             : 
    8317             :     case eExpectingEmptyToken3: {
    8318           0 :       MOZ_ASSERT(mSchemeType == eFile);
    8319             : 
    8320           0 :       if (!aToken.IsEmpty()) {
    8321           0 :         QM_WARNING("Expected the third empty token!");
    8322             : 
    8323           0 :         mError = true;
    8324           0 :         return;
    8325             :       }
    8326             : 
    8327           0 :       mState = mTokenizer.hasMoreTokens()
    8328           0 :                  ? eExpectingEmptyTokenOrDriveLetterOrPathnameComponent
    8329             :                  : eComplete;
    8330             : 
    8331           0 :       return;
    8332             :     }
    8333             : 
    8334             :     case eExpectingHost: {
    8335           0 :       if (aToken.IsEmpty()) {
    8336           0 :         QM_WARNING("Expected a host (not an empty string)!");
    8337             : 
    8338           0 :         mError = true;
    8339           0 :         return;
    8340             :       }
    8341             : 
    8342           0 :       mHost = aToken;
    8343             : 
    8344           0 :       mState = mTokenizer.hasMoreTokens() ? eExpectingPort : eComplete;
    8345             : 
    8346           0 :       return;
    8347             :     }
    8348             : 
    8349             :     case eExpectingPort: {
    8350           0 :       MOZ_ASSERT(mSchemeType == eNone);
    8351             : 
    8352           0 :       if (aToken.IsEmpty()) {
    8353           0 :         QM_WARNING("Expected a port (not an empty string)!");
    8354             : 
    8355           0 :         mError = true;
    8356           0 :         return;
    8357             :       }
    8358             : 
    8359             :       // nsDependentCSubstring doesn't provice ToInteger()
    8360           0 :       nsCString token(aToken);
    8361             : 
    8362             :       nsresult rv;
    8363           0 :       uint32_t port = token.ToInteger(&rv);
    8364           0 :       if (NS_SUCCEEDED(rv)) {
    8365           0 :         mPort.SetValue() = port;
    8366             :       } else {
    8367           0 :         QM_WARNING("'%s' is not a valid port number!", token.get());
    8368             : 
    8369           0 :         mError = true;
    8370           0 :         return;
    8371             :       }
    8372             : 
    8373           0 :       mState = eComplete;
    8374             : 
    8375           0 :       return;
    8376             :     }
    8377             : 
    8378             :     case eExpectingEmptyTokenOrDriveLetterOrPathnameComponent: {
    8379           0 :       MOZ_ASSERT(mSchemeType == eFile);
    8380             : 
    8381           0 :       if (aToken.IsEmpty()) {
    8382           0 :         mPathnameComponents.AppendElement(EmptyCString());
    8383             : 
    8384           0 :         mState =
    8385           0 :           mTokenizer.hasMoreTokens() ? eExpectingEmptyTokenOrPathnameComponent
    8386             :                                      : eComplete;
    8387             : 
    8388           0 :         return;
    8389             :       }
    8390             : 
    8391           0 :       if (aToken.Length() == 1 && NS_IsAsciiAlpha(aToken.First())) {
    8392           0 :         mMaybeDriveLetter = true;
    8393             : 
    8394           0 :         mPathnameComponents.AppendElement(aToken);
    8395             : 
    8396           0 :         mState =
    8397           0 :           mTokenizer.hasMoreTokens() ? eExpectingEmptyTokenOrPathnameComponent
    8398             :                                      : eComplete;
    8399             : 
    8400           0 :         return;
    8401             :       }
    8402             : 
    8403           0 :       HandlePathnameComponent(aToken);
    8404             : 
    8405           0 :       return;
    8406             :     }
    8407             : 
    8408             :     case eExpectingEmptyTokenOrPathnameComponent: {
    8409           0 :       MOZ_ASSERT(mSchemeType == eFile);
    8410             : 
    8411           0 :       if (aToken.IsEmpty()) {
    8412           0 :         if (mMaybeDriveLetter) {
    8413           0 :           MOZ_ASSERT(mPathnameComponents.Length() == 1);
    8414             : 
    8415           0 :           nsCString& pathnameComponent = mPathnameComponents[0];
    8416           0 :           pathnameComponent.Append(':');
    8417             : 
    8418           0 :           mMaybeDriveLetter = false;
    8419             :         } else {
    8420           0 :           mPathnameComponents.AppendElement(EmptyCString());
    8421             :         }
    8422             : 
    8423           0 :         mState =
    8424           0 :           mTokenizer.hasMoreTokens() ? eExpectingEmptyTokenOrPathnameComponent
    8425             :                                      : eComplete;
    8426             : 
    8427           0 :         return;
    8428             :       }
    8429             : 
    8430           0 :       HandlePathnameComponent(aToken);
    8431             : 
    8432           0 :       return;
    8433             :     }
    8434             : 
    8435             :     default:
    8436           0 :       MOZ_CRASH("Should never get here!");
    8437             :   }
    8438             : }
    8439             : 
    8440             : void
    8441           0 : OriginParser::HandleTrailingSeparator()
    8442             : {
    8443           0 :   MOZ_ASSERT(mState == eComplete);
    8444           0 :   MOZ_ASSERT(mSchemeType == eFile);
    8445             : 
    8446           0 :   mPathnameComponents.AppendElement(EmptyCString());
    8447             : 
    8448           0 :   mState = eHandledTrailingSeparator;
    8449           0 : }
    8450             : 
    8451             : nsresult
    8452           0 : CreateOrUpgradeDirectoryMetadataHelper::CreateOrUpgradeMetadataFiles()
    8453             : {
    8454           0 :   AssertIsOnIOThread();
    8455             : 
    8456             :   bool exists;
    8457           0 :   nsresult rv = mDirectory->Exists(&exists);
    8458           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8459           0 :     return rv;
    8460             :   }
    8461             : 
    8462           0 :   if (!exists) {
    8463           0 :     return NS_OK;
    8464             :   }
    8465             : 
    8466           0 :   nsCOMPtr<nsISimpleEnumerator> entries;
    8467           0 :   rv = mDirectory->GetDirectoryEntries(getter_AddRefs(entries));
    8468           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8469           0 :     return rv;
    8470             :   }
    8471             : 
    8472             :   bool hasMore;
    8473           0 :   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
    8474           0 :     nsCOMPtr<nsISupports> entry;
    8475           0 :     rv = entries->GetNext(getter_AddRefs(entry));
    8476           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8477           0 :       return rv;
    8478             :     }
    8479             : 
    8480           0 :     nsCOMPtr<nsIFile> originDir = do_QueryInterface(entry);
    8481           0 :     MOZ_ASSERT(originDir);
    8482             : 
    8483           0 :     nsString leafName;
    8484           0 :     rv = originDir->GetLeafName(leafName);
    8485           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8486           0 :       return rv;
    8487             :     }
    8488             : 
    8489             :     bool isDirectory;
    8490           0 :     rv = originDir->IsDirectory(&isDirectory);
    8491           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8492           0 :       return rv;
    8493             :     }
    8494             : 
    8495           0 :     if (isDirectory) {
    8496           0 :       if (leafName.EqualsLiteral("moz-safe-about+++home")) {
    8497             :         // This directory was accidentally created by a buggy nightly and can
    8498             :         // be safely removed.
    8499             : 
    8500           0 :         QM_WARNING("Deleting accidental moz-safe-about+++home directory!");
    8501             : 
    8502           0 :         rv = originDir->Remove(/* aRecursive */ true);
    8503           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    8504           0 :           return rv;
    8505             :         }
    8506             : 
    8507           0 :         continue;
    8508             :       }
    8509             :     } else {
    8510             :       // Unknown files during upgrade are allowed. Just warn if we find them.
    8511           0 :       if (!IsOSMetadata(leafName)) {
    8512           0 :         UNKNOWN_FILE_WARNING(leafName);
    8513             :       }
    8514           0 :       continue;
    8515             :     }
    8516             : 
    8517           0 :     if (mPersistent) {
    8518           0 :       rv = MaybeUpgradeOriginDirectory(originDir);
    8519           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    8520           0 :         return rv;
    8521             :       }
    8522             :     }
    8523             : 
    8524           0 :     OriginProps originProps;
    8525           0 :     rv = originProps.Init(originDir);
    8526           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8527           0 :       return rv;
    8528             :     }
    8529             : 
    8530           0 :     if (!mPersistent) {
    8531             :       int64_t timestamp;
    8532           0 :       nsCString group;
    8533           0 :       nsCString origin;
    8534           0 :       Nullable<bool> isApp;
    8535           0 :       rv = GetDirectoryMetadata(originDir,
    8536             :                                 timestamp,
    8537             :                                 group,
    8538             :                                 origin,
    8539           0 :                                 isApp);
    8540           0 :       if (NS_FAILED(rv)) {
    8541           0 :         originProps.mTimestamp = GetLastModifiedTime(originDir, mPersistent);
    8542           0 :         originProps.mNeedsRestore = true;
    8543           0 :       } else if (!isApp.IsNull()) {
    8544           0 :         originProps.mIgnore = true;
    8545             :       }
    8546             :     }
    8547             :     else {
    8548           0 :       bool persistent = QuotaManager::IsOriginInternal(originProps.mSpec);
    8549           0 :       originProps.mTimestamp = GetLastModifiedTime(originDir, persistent);
    8550             :     }
    8551             : 
    8552           0 :     mOriginProps.AppendElement(Move(originProps));
    8553             :   }
    8554             : 
    8555           0 :   if (mOriginProps.IsEmpty()) {
    8556           0 :     return NS_OK;
    8557             :   }
    8558             : 
    8559           0 :   rv = ProcessOriginDirectories();
    8560           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8561           0 :     return rv;
    8562             :   }
    8563             : 
    8564           0 :   return NS_OK;
    8565             : }
    8566             : 
    8567             : nsresult
    8568           0 : CreateOrUpgradeDirectoryMetadataHelper::MaybeUpgradeOriginDirectory(
    8569             :                                                             nsIFile* aDirectory)
    8570             : {
    8571           0 :   AssertIsOnIOThread();
    8572           0 :   MOZ_ASSERT(aDirectory);
    8573             : 
    8574           0 :   nsCOMPtr<nsIFile> metadataFile;
    8575           0 :   nsresult rv = aDirectory->Clone(getter_AddRefs(metadataFile));
    8576           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8577           0 :     return rv;
    8578             :   }
    8579             : 
    8580           0 :   rv = metadataFile->Append(NS_LITERAL_STRING(METADATA_FILE_NAME));
    8581           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8582           0 :     return rv;
    8583             :   }
    8584             : 
    8585             :   bool exists;
    8586           0 :   rv = metadataFile->Exists(&exists);
    8587           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8588           0 :     return rv;
    8589             :   }
    8590             : 
    8591           0 :   if (!exists) {
    8592             :     // Directory structure upgrade needed.
    8593             :     // Move all files to IDB specific directory.
    8594             : 
    8595           0 :     nsString idbDirectoryName;
    8596           0 :     rv = Client::TypeToText(Client::IDB, idbDirectoryName);
    8597           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8598           0 :       return rv;
    8599             :     }
    8600             : 
    8601           0 :     nsCOMPtr<nsIFile> idbDirectory;
    8602           0 :     rv = aDirectory->Clone(getter_AddRefs(idbDirectory));
    8603           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8604           0 :       return rv;
    8605             :     }
    8606             : 
    8607           0 :     rv = idbDirectory->Append(idbDirectoryName);
    8608           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8609           0 :       return rv;
    8610             :     }
    8611             : 
    8612           0 :     rv = idbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
    8613           0 :     if (rv == NS_ERROR_FILE_ALREADY_EXISTS) {
    8614           0 :       NS_WARNING("IDB directory already exists!");
    8615             : 
    8616             :       bool isDirectory;
    8617           0 :       rv = idbDirectory->IsDirectory(&isDirectory);
    8618           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    8619           0 :         return rv;
    8620             :       }
    8621             : 
    8622           0 :       if (NS_WARN_IF(!isDirectory)) {
    8623           0 :         return NS_ERROR_UNEXPECTED;
    8624             :       }
    8625             :     }
    8626             :     else {
    8627           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    8628           0 :         return rv;
    8629             :       }
    8630             :     }
    8631             : 
    8632           0 :     nsCOMPtr<nsISimpleEnumerator> entries;
    8633           0 :     rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
    8634           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8635           0 :       return rv;
    8636             :     }
    8637             : 
    8638             :     bool hasMore;
    8639           0 :     while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
    8640           0 :       nsCOMPtr<nsISupports> entry;
    8641           0 :       rv = entries->GetNext(getter_AddRefs(entry));
    8642           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    8643           0 :         return rv;
    8644             :       }
    8645             : 
    8646           0 :       nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
    8647           0 :       if (NS_WARN_IF(!file)) {
    8648           0 :         return rv;
    8649             :       }
    8650             : 
    8651           0 :       nsString leafName;
    8652           0 :       rv = file->GetLeafName(leafName);
    8653           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    8654           0 :         return rv;
    8655             :       }
    8656             : 
    8657           0 :       if (!leafName.Equals(idbDirectoryName)) {
    8658           0 :         rv = file->MoveTo(idbDirectory, EmptyString());
    8659           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    8660           0 :           return rv;
    8661             :         }
    8662             :       }
    8663             :     }
    8664             : 
    8665           0 :     rv = metadataFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
    8666           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8667           0 :       return rv;
    8668             :     }
    8669             :   }
    8670             : 
    8671           0 :   return NS_OK;
    8672             : }
    8673             : 
    8674             : nsresult
    8675           0 : CreateOrUpgradeDirectoryMetadataHelper::ProcessOriginDirectory(
    8676             :                                                 const OriginProps& aOriginProps)
    8677             : {
    8678           0 :   AssertIsOnIOThread();
    8679             : 
    8680             :   nsresult rv;
    8681             : 
    8682           0 :   if (mPersistent) {
    8683           0 :     rv = CreateDirectoryMetadata(aOriginProps.mDirectory,
    8684           0 :                                  aOriginProps.mTimestamp,
    8685             :                                  aOriginProps.mSuffix,
    8686             :                                  aOriginProps.mGroup,
    8687             :                                  aOriginProps.mOrigin);
    8688           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8689           0 :       return rv;
    8690             :     }
    8691             : 
    8692             :     // Move internal origins to new persistent storage.
    8693           0 :     if (QuotaManager::IsOriginInternal(aOriginProps.mSpec)) {
    8694           0 :       if (!mPermanentStorageDir) {
    8695             :         mPermanentStorageDir =
    8696           0 :           do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    8697           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    8698           0 :           return rv;
    8699             :         }
    8700             : 
    8701           0 :         QuotaManager* quotaManager = QuotaManager::Get();
    8702           0 :         MOZ_ASSERT(quotaManager);
    8703             : 
    8704             :         const nsString& permanentStoragePath =
    8705           0 :           quotaManager->GetStoragePath(PERSISTENCE_TYPE_PERSISTENT);
    8706             : 
    8707           0 :         rv = mPermanentStorageDir->InitWithPath(permanentStoragePath);
    8708           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    8709           0 :           return rv;
    8710             :         }
    8711             :       }
    8712             : 
    8713           0 :       nsString leafName;
    8714           0 :       rv = aOriginProps.mDirectory->GetLeafName(leafName);
    8715           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    8716           0 :         return rv;
    8717             :       }
    8718             : 
    8719           0 :       nsCOMPtr<nsIFile> newDirectory;
    8720           0 :       rv = mPermanentStorageDir->Clone(getter_AddRefs(newDirectory));
    8721           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    8722           0 :         return rv;
    8723             :       }
    8724             : 
    8725           0 :       rv = newDirectory->Append(leafName);
    8726           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    8727           0 :         return rv;
    8728             :       }
    8729             : 
    8730             :       bool exists;
    8731           0 :       rv = newDirectory->Exists(&exists);
    8732           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    8733           0 :         return rv;
    8734             :       }
    8735             : 
    8736           0 :       if (exists) {
    8737           0 :         QM_WARNING("Found %s in storage/persistent and storage/permanent !",
    8738             :                    NS_ConvertUTF16toUTF8(leafName).get());
    8739             : 
    8740           0 :         rv = aOriginProps.mDirectory->Remove(/* recursive */ true);
    8741             :       } else {
    8742           0 :         rv = aOriginProps.mDirectory->MoveTo(mPermanentStorageDir,
    8743           0 :                                              EmptyString());
    8744             :       }
    8745           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    8746           0 :         return rv;
    8747             :       }
    8748             :     }
    8749           0 :   } else if (aOriginProps.mNeedsRestore) {
    8750           0 :     rv = CreateDirectoryMetadata(aOriginProps.mDirectory,
    8751           0 :                                  aOriginProps.mTimestamp,
    8752             :                                  aOriginProps.mSuffix,
    8753             :                                  aOriginProps.mGroup,
    8754             :                                  aOriginProps.mOrigin);
    8755           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8756           0 :       return rv;
    8757             :     }
    8758           0 :   } else if (!aOriginProps.mIgnore) {
    8759           0 :     nsCOMPtr<nsIFile> file;
    8760           0 :     rv = aOriginProps.mDirectory->Clone(getter_AddRefs(file));
    8761           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8762           0 :       return rv;
    8763             :     }
    8764             : 
    8765           0 :     rv = file->Append(NS_LITERAL_STRING(METADATA_FILE_NAME));
    8766           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8767           0 :       return rv;
    8768             :     }
    8769             : 
    8770           0 :     nsCOMPtr<nsIBinaryOutputStream> stream;
    8771           0 :     rv = GetBinaryOutputStream(file, kAppendFileFlag, getter_AddRefs(stream));
    8772           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8773           0 :       return rv;
    8774             :     }
    8775             : 
    8776           0 :     MOZ_ASSERT(stream);
    8777             : 
    8778             :     // Currently unused (used to be isApp).
    8779           0 :     rv = stream->WriteBoolean(false);
    8780           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8781           0 :       return rv;
    8782             :     }
    8783             :   }
    8784             : 
    8785           0 :   return NS_OK;
    8786             : }
    8787             : 
    8788             : nsresult
    8789           0 : UpgradeStorageFrom0_0To1_0Helper::DoUpgrade()
    8790             : {
    8791           0 :   AssertIsOnIOThread();
    8792             : 
    8793             :   bool exists;
    8794           0 :   nsresult rv = mDirectory->Exists(&exists);
    8795           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8796           0 :     return rv;
    8797             :   }
    8798             : 
    8799           0 :   if (!exists) {
    8800           0 :     return NS_OK;
    8801             :   }
    8802             : 
    8803           0 :   nsCOMPtr<nsISimpleEnumerator> entries;
    8804           0 :   rv = mDirectory->GetDirectoryEntries(getter_AddRefs(entries));
    8805           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8806           0 :     return rv;
    8807             :   }
    8808             : 
    8809             :   bool hasMore;
    8810           0 :   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
    8811           0 :     nsCOMPtr<nsISupports> entry;
    8812           0 :     rv = entries->GetNext(getter_AddRefs(entry));
    8813           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8814           0 :       return rv;
    8815             :     }
    8816             : 
    8817           0 :     nsCOMPtr<nsIFile> originDir = do_QueryInterface(entry);
    8818           0 :     MOZ_ASSERT(originDir);
    8819             : 
    8820             :     bool isDirectory;
    8821           0 :     rv = originDir->IsDirectory(&isDirectory);
    8822           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8823           0 :       return rv;
    8824             :     }
    8825             : 
    8826           0 :     if (!isDirectory) {
    8827           0 :       nsString leafName;
    8828           0 :       rv = originDir->GetLeafName(leafName);
    8829           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    8830           0 :         return rv;
    8831             :       }
    8832             : 
    8833             :       // Unknown files during upgrade are allowed. Just warn if we find them.
    8834           0 :       if (!IsOSMetadata(leafName)) {
    8835           0 :         UNKNOWN_FILE_WARNING(leafName);
    8836             :       }
    8837           0 :       continue;
    8838             :     }
    8839             : 
    8840           0 :     OriginProps originProps;
    8841           0 :     rv = originProps.Init(originDir);
    8842           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8843           0 :       return rv;
    8844             :     }
    8845             : 
    8846             :     int64_t timestamp;
    8847           0 :     nsCString group;
    8848           0 :     nsCString origin;
    8849           0 :     Nullable<bool> isApp;
    8850           0 :     nsresult rv = GetDirectoryMetadata(originDir,
    8851             :                                        timestamp,
    8852             :                                        group,
    8853             :                                        origin,
    8854           0 :                                        isApp);
    8855           0 :     if (NS_FAILED(rv) || isApp.IsNull()) {
    8856           0 :       originProps.mTimestamp = GetLastModifiedTime(originDir, mPersistent);
    8857           0 :       originProps.mNeedsRestore = true;
    8858             :     } else {
    8859           0 :       originProps.mTimestamp = timestamp;
    8860             :     }
    8861             : 
    8862           0 :     mOriginProps.AppendElement(Move(originProps));
    8863             :   }
    8864             : 
    8865           0 :   if (mOriginProps.IsEmpty()) {
    8866           0 :     return NS_OK;
    8867             :   }
    8868             : 
    8869           0 :   rv = ProcessOriginDirectories();
    8870           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8871           0 :     return rv;
    8872             :   }
    8873             : 
    8874           0 :   return NS_OK;
    8875             : }
    8876             : 
    8877             : nsresult
    8878           0 : UpgradeStorageFrom0_0To1_0Helper::ProcessOriginDirectory(
    8879             :                                                 const OriginProps& aOriginProps)
    8880             : {
    8881           0 :   AssertIsOnIOThread();
    8882             : 
    8883             :   nsresult rv;
    8884             : 
    8885           0 :   if (aOriginProps.mNeedsRestore) {
    8886           0 :     rv = CreateDirectoryMetadata(aOriginProps.mDirectory,
    8887           0 :                                  aOriginProps.mTimestamp,
    8888             :                                  aOriginProps.mSuffix,
    8889             :                                  aOriginProps.mGroup,
    8890           0 :                                  aOriginProps.mOrigin);
    8891           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8892           0 :       return rv;
    8893             :     }
    8894             :   }
    8895             : 
    8896           0 :   rv = CreateDirectoryMetadata2(aOriginProps.mDirectory,
    8897           0 :                                 aOriginProps.mTimestamp,
    8898             :                                 /* aPersisted */ false,
    8899             :                                 aOriginProps.mSuffix,
    8900             :                                 aOriginProps.mGroup,
    8901           0 :                                 aOriginProps.mOrigin);
    8902           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8903           0 :     return rv;
    8904             :   }
    8905             : 
    8906           0 :   nsString oldName;
    8907           0 :   rv = aOriginProps.mDirectory->GetLeafName(oldName);
    8908           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8909           0 :     return rv;
    8910             :   }
    8911             : 
    8912           0 :   nsAutoCString originSanitized(aOriginProps.mOrigin);
    8913           0 :   SanitizeOriginString(originSanitized);
    8914             : 
    8915           0 :   NS_ConvertASCIItoUTF16 newName(originSanitized);
    8916             : 
    8917           0 :   if (!oldName.Equals(newName)) {
    8918           0 :     rv = aOriginProps.mDirectory->RenameTo(nullptr, newName);
    8919           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8920           0 :       return rv;
    8921             :     }
    8922             :   }
    8923             : 
    8924           0 :   return NS_OK;
    8925             : }
    8926             : 
    8927             : nsresult
    8928           0 : UpgradeStorageFrom1_0To2_0Helper::DoUpgrade()
    8929             : {
    8930           0 :   AssertIsOnIOThread();
    8931             : 
    8932           0 :   DebugOnly<bool> exists;
    8933           0 :   MOZ_ASSERT(NS_SUCCEEDED(mDirectory->Exists(&exists)));
    8934           0 :   MOZ_ASSERT(exists);
    8935             : 
    8936           0 :   nsCOMPtr<nsISimpleEnumerator> entries;
    8937           0 :   nsresult rv = mDirectory->GetDirectoryEntries(getter_AddRefs(entries));
    8938           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8939           0 :     return rv;
    8940             :   }
    8941             : 
    8942             :   bool hasMore;
    8943           0 :   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
    8944           0 :     nsCOMPtr<nsISupports> entry;
    8945           0 :     rv = entries->GetNext(getter_AddRefs(entry));
    8946           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8947           0 :       return rv;
    8948             :     }
    8949             : 
    8950           0 :     nsCOMPtr<nsIFile> originDir = do_QueryInterface(entry);
    8951           0 :     MOZ_ASSERT(originDir);
    8952             : 
    8953             :     bool isDirectory;
    8954           0 :     rv = originDir->IsDirectory(&isDirectory);
    8955           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8956           0 :       return rv;
    8957             :     }
    8958             : 
    8959           0 :     if (!isDirectory) {
    8960           0 :       nsString leafName;
    8961           0 :       rv = originDir->GetLeafName(leafName);
    8962           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    8963           0 :         return rv;
    8964             :       }
    8965             : 
    8966             :       // Unknown files during upgrade are allowed. Just warn if we find them.
    8967           0 :       if (!IsOSMetadata(leafName)) {
    8968           0 :         UNKNOWN_FILE_WARNING(leafName);
    8969             :       }
    8970           0 :       continue;
    8971             :     }
    8972             : 
    8973           0 :     OriginProps originProps;
    8974           0 :     rv = originProps.Init(originDir);
    8975           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8976           0 :       return rv;
    8977             :     }
    8978             : 
    8979           0 :     rv = MaybeUpgradeClients(originProps);
    8980           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8981           0 :       return rv;
    8982             :     }
    8983             : 
    8984             :     bool removed;
    8985           0 :     rv = MaybeRemoveAppsData(originProps, &removed);
    8986           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    8987           0 :       return rv;
    8988             :     }
    8989           0 :     if (removed) {
    8990           0 :       continue;
    8991             :     }
    8992             : 
    8993             :     int64_t timestamp;
    8994           0 :     nsCString group;
    8995           0 :     nsCString origin;
    8996           0 :     Nullable<bool> isApp;
    8997           0 :     nsresult rv = GetDirectoryMetadata(originDir,
    8998             :                                        timestamp,
    8999             :                                        group,
    9000             :                                        origin,
    9001           0 :                                        isApp);
    9002           0 :     if (NS_FAILED(rv) || isApp.IsNull()) {
    9003           0 :       originProps.mNeedsRestore = true;
    9004             :     }
    9005             : 
    9006           0 :     nsCString suffix;
    9007           0 :     rv = GetDirectoryMetadata2(originDir,
    9008             :                                timestamp,
    9009             :                                suffix,
    9010             :                                group,
    9011             :                                origin,
    9012           0 :                                isApp.SetValue());
    9013           0 :     if (NS_FAILED(rv)) {
    9014           0 :       originProps.mTimestamp = GetLastModifiedTime(originDir, mPersistent);
    9015           0 :       originProps.mNeedsRestore2 = true;
    9016             :     } else {
    9017           0 :       originProps.mTimestamp = timestamp;
    9018             :     }
    9019             : 
    9020           0 :     mOriginProps.AppendElement(Move(originProps));
    9021             :   }
    9022           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9023           0 :     return rv;
    9024             :   }
    9025             : 
    9026           0 :   if (mOriginProps.IsEmpty()) {
    9027           0 :     return NS_OK;
    9028             :   }
    9029             : 
    9030           0 :   rv = ProcessOriginDirectories();
    9031           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9032           0 :     return rv;
    9033             :   }
    9034             : 
    9035           0 :   return NS_OK;
    9036             : }
    9037             : 
    9038             : nsresult
    9039           0 : UpgradeStorageFrom1_0To2_0Helper::MaybeUpgradeClients(
    9040             :                                                 const OriginProps& aOriginProps)
    9041             : {
    9042           0 :   AssertIsOnIOThread();
    9043           0 :   MOZ_ASSERT(aOriginProps.mDirectory);
    9044             : 
    9045           0 :   QuotaManager* quotaManager = QuotaManager::Get();
    9046           0 :   MOZ_ASSERT(quotaManager);
    9047             : 
    9048           0 :   nsCOMPtr<nsISimpleEnumerator> entries;
    9049             :   nsresult rv =
    9050           0 :     aOriginProps.mDirectory->GetDirectoryEntries(getter_AddRefs(entries));
    9051           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9052           0 :     return rv;
    9053             :   }
    9054             : 
    9055             :   bool hasMore;
    9056           0 :   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
    9057           0 :     nsCOMPtr<nsISupports> entry;
    9058           0 :     rv = entries->GetNext(getter_AddRefs(entry));
    9059           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    9060           0 :       return rv;
    9061             :     }
    9062             : 
    9063           0 :     nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
    9064           0 :     if (NS_WARN_IF(!file)) {
    9065           0 :       return rv;
    9066             :     }
    9067             : 
    9068             :     bool isDirectory;
    9069           0 :     rv = file->IsDirectory(&isDirectory);
    9070           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    9071           0 :       return rv;
    9072             :     }
    9073             : 
    9074           0 :     nsString leafName;
    9075           0 :     rv = file->GetLeafName(leafName);
    9076           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    9077           0 :       return rv;
    9078             :     }
    9079             : 
    9080           0 :     if (!isDirectory) {
    9081             :       // Unknown files during upgrade are allowed. Just warn if we find them.
    9082           0 :       if (!IsOriginMetadata(leafName) &&
    9083           0 :           !IsTempMetadata(leafName)) {
    9084           0 :         UNKNOWN_FILE_WARNING(leafName);
    9085             :       }
    9086           0 :       continue;
    9087             :     }
    9088             : 
    9089             :     // The Cache API was creating top level morgue directories by accident for
    9090             :     // a short time in nightly.  This unfortunately prevents all storage from
    9091             :     // working.  So recover these profiles permanently by removing these corrupt
    9092             :     // directories as part of this upgrade.
    9093           0 :     if (leafName.EqualsLiteral("morgue")) {
    9094           0 :       QM_WARNING("Deleting accidental morgue directory!");
    9095             : 
    9096           0 :       rv = file->Remove(/* recursive */ true);
    9097           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    9098           0 :         return rv;
    9099             :       }
    9100             : 
    9101           0 :       continue;
    9102             :     }
    9103             : 
    9104             :     Client::Type clientType;
    9105           0 :     rv = Client::TypeFromText(leafName, clientType);
    9106           0 :     if (NS_FAILED(rv)) {
    9107           0 :       UNKNOWN_FILE_WARNING(leafName);
    9108           0 :       continue;
    9109             :     }
    9110             : 
    9111           0 :     Client* client = quotaManager->GetClient(clientType);
    9112           0 :     MOZ_ASSERT(client);
    9113             : 
    9114           0 :     rv = client->UpgradeStorageFrom1_0To2_0(file);
    9115           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    9116           0 :       return rv;
    9117             :     }
    9118             :   }
    9119           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9120           0 :     return rv;
    9121             :   }
    9122             : 
    9123           0 :   return NS_OK;
    9124             : }
    9125             : 
    9126             : nsresult
    9127           0 : UpgradeStorageFrom1_0To2_0Helper::MaybeRemoveAppsData(
    9128             :                                                 const OriginProps& aOriginProps,
    9129             :                                                 bool* aRemoved)
    9130             : {
    9131           0 :   AssertIsOnIOThread();
    9132             : 
    9133             :   // XXX This will need to be reworked as part of bug 1320404 (appId is
    9134             :   //     going to be removed from origin attributes).
    9135           0 :   if (aOriginProps.mAttrs.mAppId != kNoAppId &&
    9136           0 :       aOriginProps.mAttrs.mAppId != kUnknownAppId) {
    9137           0 :     nsresult rv = RemoveObsoleteOrigin(aOriginProps);
    9138           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    9139           0 :       return rv;
    9140             :     }
    9141             : 
    9142           0 :     *aRemoved = true;
    9143           0 :     return NS_OK;
    9144             :   }
    9145             : 
    9146           0 :   *aRemoved = false;
    9147           0 :   return NS_OK;
    9148             : }
    9149             : 
    9150             : nsresult
    9151           0 : UpgradeStorageFrom1_0To2_0Helper::MaybeStripObsoleteOriginAttributes(
    9152             :                                                 const OriginProps& aOriginProps,
    9153             :                                                 bool* aStripped)
    9154             : {
    9155           0 :   AssertIsOnIOThread();
    9156           0 :   MOZ_ASSERT(aOriginProps.mDirectory);
    9157             : 
    9158           0 :   const nsAString& oldLeafName = aOriginProps.mLeafName;
    9159             : 
    9160           0 :   nsCString originSanitized(aOriginProps.mOrigin);
    9161           0 :   SanitizeOriginString(originSanitized);
    9162             : 
    9163           0 :   NS_ConvertUTF8toUTF16 newLeafName(originSanitized);
    9164             : 
    9165           0 :   if (oldLeafName == newLeafName) {
    9166           0 :     *aStripped = false;
    9167           0 :     return NS_OK;
    9168             :   }
    9169             : 
    9170           0 :   nsresult rv = CreateDirectoryMetadata(aOriginProps.mDirectory,
    9171           0 :                                         aOriginProps.mTimestamp,
    9172             :                                         aOriginProps.mSuffix,
    9173             :                                         aOriginProps.mGroup,
    9174           0 :                                         aOriginProps.mOrigin);
    9175           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9176           0 :     return rv;
    9177             :   }
    9178             : 
    9179           0 :   rv = CreateDirectoryMetadata2(aOriginProps.mDirectory,
    9180           0 :                                 aOriginProps.mTimestamp,
    9181             :                                 /* aPersisted */ false,
    9182             :                                 aOriginProps.mSuffix,
    9183             :                                 aOriginProps.mGroup,
    9184           0 :                                 aOriginProps.mOrigin);
    9185           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9186           0 :     return rv;
    9187             :   }
    9188             : 
    9189           0 :   nsCOMPtr<nsIFile> newFile;
    9190           0 :   rv = aOriginProps.mDirectory->GetParent(getter_AddRefs(newFile));
    9191           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9192           0 :     return rv;
    9193             :   }
    9194             : 
    9195           0 :   rv = newFile->Append(newLeafName);
    9196           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9197           0 :     return rv;
    9198             :   }
    9199             : 
    9200             :   bool exists;
    9201           0 :   rv = newFile->Exists(&exists);
    9202           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9203           0 :     return rv;
    9204             :   }
    9205             : 
    9206           0 :   if (exists) {
    9207           0 :     QM_WARNING("Can't rename %s directory, %s directory already exists, "
    9208             :                "removing!",
    9209             :                NS_ConvertUTF16toUTF8(oldLeafName).get(),
    9210             :                NS_ConvertUTF16toUTF8(newLeafName).get());
    9211             : 
    9212           0 :     rv = aOriginProps.mDirectory->Remove(/* recursive */ true);
    9213             :   } else {
    9214           0 :     rv = aOriginProps.mDirectory->RenameTo(nullptr, newLeafName);
    9215             :   }
    9216           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9217           0 :     return rv;
    9218             :   }
    9219             : 
    9220           0 :   *aStripped = true;
    9221           0 :   return NS_OK;
    9222             : }
    9223             : 
    9224             : nsresult
    9225           0 : UpgradeStorageFrom1_0To2_0Helper::ProcessOriginDirectory(
    9226             :                                                 const OriginProps& aOriginProps)
    9227             : {
    9228           0 :   AssertIsOnIOThread();
    9229             : 
    9230             :   bool stripped;
    9231           0 :   nsresult rv = MaybeStripObsoleteOriginAttributes(aOriginProps, &stripped);
    9232           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9233           0 :     return rv;
    9234             :   }
    9235           0 :   if (stripped) {
    9236           0 :     return NS_OK;
    9237             :   }
    9238             : 
    9239           0 :   if (aOriginProps.mNeedsRestore) {
    9240           0 :     rv = CreateDirectoryMetadata(aOriginProps.mDirectory,
    9241           0 :                                  aOriginProps.mTimestamp,
    9242             :                                  aOriginProps.mSuffix,
    9243             :                                  aOriginProps.mGroup,
    9244           0 :                                  aOriginProps.mOrigin);
    9245           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    9246           0 :       return rv;
    9247             :     }
    9248             :   }
    9249             : 
    9250           0 :   if (aOriginProps.mNeedsRestore2) {
    9251           0 :     rv = CreateDirectoryMetadata2(aOriginProps.mDirectory,
    9252           0 :                                   aOriginProps.mTimestamp,
    9253             :                                   /* aPersisted */ false,
    9254             :                                   aOriginProps.mSuffix,
    9255             :                                   aOriginProps.mGroup,
    9256           0 :                                   aOriginProps.mOrigin);
    9257           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    9258           0 :       return rv;
    9259             :     }
    9260             :   }
    9261             : 
    9262           0 :   return NS_OK;
    9263             : }
    9264             : 
    9265             : nsresult
    9266           0 : RestoreDirectoryMetadata2Helper::RestoreMetadata2File()
    9267             : {
    9268           0 :   AssertIsOnIOThread();
    9269             : 
    9270             :   nsresult rv;
    9271             : 
    9272           0 :   OriginProps originProps;
    9273           0 :   rv = originProps.Init(mDirectory);
    9274           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9275           0 :     return rv;
    9276             :   }
    9277             : 
    9278           0 :   originProps.mTimestamp = GetLastModifiedTime(mDirectory, mPersistent);
    9279             : 
    9280           0 :   mOriginProps.AppendElement(Move(originProps));
    9281             : 
    9282           0 :   rv = ProcessOriginDirectories();
    9283           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9284           0 :     return rv;
    9285             :   }
    9286             : 
    9287           0 :   return NS_OK;
    9288             : }
    9289             : 
    9290             : nsresult
    9291           0 : RestoreDirectoryMetadata2Helper::ProcessOriginDirectory(
    9292             :                                                 const OriginProps& aOriginProps)
    9293             : {
    9294           0 :   AssertIsOnIOThread();
    9295             : 
    9296             :   // We don't have any approach to restore aPersisted, so reset it to false.
    9297           0 :   nsresult rv = CreateDirectoryMetadata2(aOriginProps.mDirectory,
    9298           0 :                                          aOriginProps.mTimestamp,
    9299             :                                          /* aPersisted */ false,
    9300             :                                          aOriginProps.mSuffix,
    9301             :                                          aOriginProps.mGroup,
    9302           0 :                                          aOriginProps.mOrigin);
    9303           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9304           0 :     return rv;
    9305             :   }
    9306             : 
    9307           0 :   return NS_OK;
    9308             : }
    9309             : 
    9310             : } // namespace quota
    9311             : } // namespace dom
    9312             : } // namespace mozilla

Generated by: LCOV version 1.13