Backed out changeset 45dad11b6580 (bug 1089764) for causing bug 1093067 and bug 1093223.
authorJan Varga <jan.varga@gmail.com>
Mon, 03 Nov 2014 21:00:52 +0100
changeset 238021 9b03757d6c99d17a5701c9e9bef1c8cd36de2ea4
parent 238020 536edab24d9999650287b15d441624b6291d65a3
child 238053 d11d6fdc785f36956f44524c9be9153e7a002596
child 238076 4dad6c124f2aa934b4197fa1870682e2b356ab39
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1089764, 1093067, 1093223
milestone36.0a1
backs out45dad11b6580464401881765f575e00f81fb136e
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 45dad11b6580 (bug 1089764) for causing bug 1093067 and bug 1093223.
dom/asmjscache/AsmJSCache.cpp
dom/base/nsDOMWindowUtils.cpp
dom/indexedDB/ActorsParent.cpp
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBMutableFile.cpp
dom/indexedDB/moz.build
dom/indexedDB/test/mochitest.ini
dom/indexedDB/test/unit/test_temporary_storage.js
dom/quota/OriginCollection.h
dom/quota/PersistenceType.h
dom/quota/QuotaManager.cpp
dom/quota/QuotaManager.h
dom/quota/QuotaObject.cpp
dom/quota/QuotaObject.h
dom/quota/StoragePrivilege.h
dom/quota/moz.build
--- a/dom/asmjscache/AsmJSCache.cpp
+++ b/dom/asmjscache/AsmJSCache.cpp
@@ -487,20 +487,17 @@ public:
   MainProcessRunnable(nsIPrincipal* aPrincipal,
                       OpenMode aOpenMode,
                       WriteParams aWriteParams)
   : mPrincipal(aPrincipal),
     mOpenMode(aOpenMode),
     mWriteParams(aWriteParams),
     mNeedAllowNextSynchronizedOp(false),
     mPersistence(quota::PERSISTENCE_TYPE_INVALID),
-    mState(eInitial),
-    mIsApp(false),
-    mHasUnlimStoragePerm(false),
-    mEnforcingQuota(true)
+    mState(eInitial)
   {
     MOZ_ASSERT(IsMainProcess());
   }
 
   virtual ~MainProcessRunnable()
   {
     MOZ_ASSERT(mState == eFinished);
     MOZ_ASSERT(!mNeedAllowNextSynchronizedOp);
@@ -591,19 +588,16 @@ protected:
   // Called by MainProcessRunnable on the main thread after a call to Close():
   virtual void
   OnClose()
   {
     FinishOnMainThread();
   }
 
 private:
-  void
-  InitPersistenceType();
-
   nsresult
   InitOnMainThread();
 
   nsresult
   ReadMetadata();
 
   nsresult
   OpenCacheFileForWrite();
@@ -660,119 +654,101 @@ private:
     eReadyToOpenCacheFileForRead, // Waiting to open cache file for read
     eSendingCacheFile, // Waiting to send OnOpenCacheFile on the main thread
     eOpened, // Finished calling OnOpen, waiting to be closed
     eClosing, // Waiting to be dispatched to main thread again
     eFailing, // Just failed, waiting to be dispatched to the main thread
     eFinished, // Terminal state
   };
   State mState;
-
-  bool mIsApp;
-  bool mHasUnlimStoragePerm;
-  bool mEnforcingQuota;
 };
 
-void
-MainProcessRunnable::InitPersistenceType()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mState == eInitial);
-
-  if (mOpenMode == eOpenForWrite) {
-    MOZ_ASSERT(mPersistence == quota::PERSISTENCE_TYPE_INVALID);
-
-    // If we are performing install-time caching of an app, we'd like to store
-    // the cache entry in persistent storage so the entry is never evicted,
-    // but we need to check that quota is not enforced for the app.
-    // That justifies us in skipping all quota checks when storing the cache
-    // entry and avoids all the issues around the persistent quota prompt.
-    // If quota is enforced for the app, then we can still cache in temporary
-    // for a likely good first-run experience.
-
-    MOZ_ASSERT_IF(mWriteParams.mInstalled, mIsApp);
-
-    if (mWriteParams.mInstalled &&
-        !QuotaManager::IsQuotaEnforced(quota::PERSISTENCE_TYPE_PERSISTENT,
-                                       mOrigin, mHasUnlimStoragePerm)) {
-      mPersistence = quota::PERSISTENCE_TYPE_PERSISTENT;
-    } else {
-      mPersistence = quota::PERSISTENCE_TYPE_TEMPORARY;
-    }
-
-    return;
-  }
-
-  // For the reasons described above, apps may have cache entries in both
-  // persistent and temporary storage. At lookup time we don't know how and
-  // where the given script was cached, so start the search in persistent
-  // storage and, if that fails, search in temporary storage. (Non-apps can
-  // only be stored in temporary storage.)
-
-  MOZ_ASSERT_IF(mPersistence != quota::PERSISTENCE_TYPE_INVALID,
-                mIsApp && mPersistence == quota::PERSISTENCE_TYPE_PERSISTENT);
-
-  if (mPersistence == quota::PERSISTENCE_TYPE_INVALID && mIsApp) {
-    mPersistence = quota::PERSISTENCE_TYPE_PERSISTENT;
-  } else {
-    mPersistence = quota::PERSISTENCE_TYPE_TEMPORARY;
-  }
-}
-
 nsresult
 MainProcessRunnable::InitOnMainThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mState == eInitial);
 
   QuotaManager* qm = QuotaManager::GetOrCreate();
   NS_ENSURE_STATE(qm);
 
-  nsresult rv =
-    QuotaManager::GetInfoFromPrincipal(mPrincipal,
-                                       quota::PERSISTENCE_TYPE_INVALID,
-                                       &mGroup, &mOrigin, &mIsApp,
-                                       &mHasUnlimStoragePerm);
+  nsresult rv = QuotaManager::GetInfoFromPrincipal(mPrincipal, &mGroup,
+                                                   &mOrigin, nullptr, nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // XXX Don't use mGroup yet! We might need to update it right after we
-  //     initialize persistence type.
+  bool isApp = mPrincipal->GetAppStatus() !=
+               nsIPrincipal::APP_STATUS_NOT_INSTALLED;
 
-  InitPersistenceType();
+  if (mOpenMode == eOpenForWrite) {
+    MOZ_ASSERT(mPersistence == quota::PERSISTENCE_TYPE_INVALID);
+    if (mWriteParams.mInstalled) {
+      // If we are performing install-time caching of an app, we'd like to store
+      // the cache entry in persistent storage so the entry is never evicted,
+      // but we need to verify that the app has unlimited storage permissions
+      // first. Unlimited storage permissions justify us in skipping all quota
+      // checks when storing the cache entry and avoids all the issues around
+      // the persistent quota prompt.
+      MOZ_ASSERT(isApp);
+
+      nsCOMPtr<nsIPermissionManager> pm =
+        services::GetPermissionManager();
+      NS_ENSURE_TRUE(pm, NS_ERROR_UNEXPECTED);
+
+      uint32_t permission;
+      rv = pm->TestPermissionFromPrincipal(mPrincipal,
+                                           PERMISSION_STORAGE_UNLIMITED,
+                                           &permission);
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
 
-  // XXX Since we couldn't pass persistence type to GetInfoFromPrincipal(),
-  //     we need to do this manually.
-  //     This hack is only temporary, it will go away once we have regular
-  //     metadata files for persistent storge.
-  if (mPersistence == quota::PERSISTENCE_TYPE_PERSISTENT) {
-    mGroup = mOrigin;
+      // If app doens't have the unlimited storage permission, we can still
+      // cache in temporary for a likely good first-run experience.
+      mPersistence = permission == nsIPermissionManager::ALLOW_ACTION
+                     ? quota::PERSISTENCE_TYPE_PERSISTENT
+                     : quota::PERSISTENCE_TYPE_TEMPORARY;
+    } else {
+      mPersistence = quota::PERSISTENCE_TYPE_TEMPORARY;
+    }
+  } else {
+    // For the reasons described above, apps may have cache entries in both
+    // persistent and temporary storage. At lookup time we don't know how and
+    // where the given script was cached, so start the search in persistent
+    // storage and, if that fails, search in temporary storage. (Non-apps can
+    // only be stored in temporary storage.)
+    if (mPersistence == quota::PERSISTENCE_TYPE_INVALID) {
+      mPersistence = isApp ? quota::PERSISTENCE_TYPE_PERSISTENT
+                           : quota::PERSISTENCE_TYPE_TEMPORARY;
+    } else {
+      MOZ_ASSERT(isApp);
+      MOZ_ASSERT(mPersistence == quota::PERSISTENCE_TYPE_PERSISTENT);
+      mPersistence = quota::PERSISTENCE_TYPE_TEMPORARY;
+    }
   }
 
-  mEnforcingQuota =
-    QuotaManager::IsQuotaEnforced(mPersistence, mOrigin, mHasUnlimStoragePerm);
-
   QuotaManager::GetStorageId(mPersistence, mOrigin, quota::Client::ASMJS,
                              NS_LITERAL_STRING("asmjs"), mStorageId);
 
   return NS_OK;
 }
 
 nsresult
 MainProcessRunnable::ReadMetadata()
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(mState == eReadyToReadMetadata);
 
   QuotaManager* qm = QuotaManager::Get();
   MOZ_ASSERT(qm, "We are on the QuotaManager's IO thread");
 
-  nsresult rv =
-    qm->EnsureOriginIsInitialized(mPersistence, mGroup, mOrigin,
-                                  mHasUnlimStoragePerm,
-                                  getter_AddRefs(mDirectory));
+  // Only track quota for temporary storage. For persistent storage, we've
+  // already checked that we have unlimited-storage permissions.
+  bool trackQuota = mPersistence == quota::PERSISTENCE_TYPE_TEMPORARY;
+
+  nsresult rv = qm->EnsureOriginIsInitialized(mPersistence, mGroup, mOrigin,
+                                              trackQuota,
+                                              getter_AddRefs(mDirectory));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mDirectory->Append(NS_LITERAL_STRING(ASMJSCACHE_DIRECTORY_NAME));
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool exists;
   rv = mDirectory->Exists(&exists);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -830,17 +806,21 @@ MainProcessRunnable::OpenCacheFileForWri
 
   nsCOMPtr<nsIFile> file;
   nsresult rv = GetCacheFile(mDirectory, mModuleIndex, getter_AddRefs(file));
   NS_ENSURE_SUCCESS(rv, rv);
 
   QuotaManager* qm = QuotaManager::Get();
   MOZ_ASSERT(qm, "We are on the QuotaManager's IO thread");
 
-  if (mEnforcingQuota) {
+  // If we are allocating in temporary storage, ask the QuotaManager if we're
+  // within the quota. If we are allocating in persistent storage, we've already
+  // checked that we have the unlimited-storage permission, so there is nothing
+  // to check.
+  if (mPersistence == quota::PERSISTENCE_TYPE_TEMPORARY) {
     // Create the QuotaObject before all file IO and keep it alive until caching
     // completes to get maximum assertion coverage in QuotaManager against
     // concurrent removal, etc.
     mQuotaObject = qm->GetQuotaObject(mPersistence, mGroup, mOrigin, file);
     NS_ENSURE_STATE(mQuotaObject);
 
     if (!mQuotaObject->MaybeAllocateMoreSpace(0, mWriteParams.mSize)) {
       // If the request fails, it might be because mOrigin is using too much
@@ -881,17 +861,17 @@ MainProcessRunnable::OpenCacheFileForRea
 
   nsCOMPtr<nsIFile> file;
   nsresult rv = GetCacheFile(mDirectory, mModuleIndex, getter_AddRefs(file));
   NS_ENSURE_SUCCESS(rv, rv);
 
   QuotaManager* qm = QuotaManager::Get();
   MOZ_ASSERT(qm, "We are on the QuotaManager's IO thread");
 
-  if (mEnforcingQuota) {
+  if (mPersistence == quota::PERSISTENCE_TYPE_TEMPORARY) {
     // Even though it's not strictly necessary, create the QuotaObject before
     // all file IO and keep it alive until caching completes to get maximum
     // assertion coverage in QuotaManager against concurrent removal, etc.
     mQuotaObject = qm->GetQuotaObject(mPersistence, mGroup, mOrigin, file);
     NS_ENSURE_STATE(mQuotaObject);
   }
 
   rv = file->GetFileSize(&mFileSize);
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -3089,30 +3089,31 @@ nsDOMWindowUtils::GetFileReferences(cons
                                     int32_t* aSliceRefCnt, JSContext* aCx,
                                     bool* aResult)
 {
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
 
+  nsCString origin;
+  quota::PersistenceType defaultPersistenceType;
+  nsresult rv =
+    quota::QuotaManager::GetInfoFromWindow(window, nullptr, &origin, nullptr,
+                                           &defaultPersistenceType);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   IDBOpenDBOptions options;
   JS::Rooted<JS::Value> optionsVal(aCx, aOptions);
   if (!options.Init(aCx, optionsVal)) {
     return NS_ERROR_TYPE_ERR;
   }
 
   quota::PersistenceType persistenceType =
-    quota::PersistenceTypeFromStorage(options.mStorage);
-
-  nsCString origin;
-  nsresult rv =
-    quota::QuotaManager::GetInfoFromWindow(window, persistenceType, nullptr,
-                                           &origin, nullptr, nullptr);
-  NS_ENSURE_SUCCESS(rv, rv);
+    quota::PersistenceTypeFromStorage(options.mStorage, defaultPersistenceType);
 
   nsRefPtr<indexedDB::IndexedDatabaseManager> mgr =
     indexedDB::IndexedDatabaseManager::Get();
 
   if (mgr) {
     rv = mgr->BlockAndGetFileReferences(persistenceType, origin, aDatabaseName,
                                         aId, aRefCnt, aDBRefCnt, aSliceRefCnt,
                                         aResult);
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ActorsParent.h"
 
 #include <algorithm>
+#include "CheckQuotaHelper.h"
 #include "FileInfo.h"
 #include "FileManager.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
 #include "IndexedDatabase.h"
 #include "IndexedDatabaseInlines.h"
 #include "IndexedDatabaseManager.h"
 #include "js/StructuredClone.h"
@@ -3886,17 +3887,16 @@ protected:
 
   nsTArray<MaybeBlockedDatabaseInfo> mMaybeBlockedDatabases;
 
   const CommonFactoryRequestParams mCommonParams;
   nsCString mGroup;
   nsCString mOrigin;
   nsCString mDatabaseId;
   State mState;
-  bool mHasUnlimStoragePerm;
   bool mEnforcingQuota;
   const bool mDeleting;
   bool mBlockedQuotaManager;
   bool mChromeWriteAccessAllowed;
 
 public:
   void
   NoteDatabaseBlocked(Database* aDatabase);
@@ -5933,22 +5933,16 @@ Factory::AllocPBackgroundIDBFactoryReque
   }
 
   const PrincipalInfo& principalInfo = commonParams->principalInfo();
   if (NS_WARN_IF(principalInfo.type() == PrincipalInfo::TNullPrincipalInfo)) {
     ASSERT_UNLESS_FUZZING();
     return nullptr;
   }
 
-  if (NS_WARN_IF(principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo &&
-                 metadata.persistenceType() != PERSISTENCE_TYPE_PERSISTENT)) {
-    ASSERT_UNLESS_FUZZING();
-    return nullptr;
-  }
-
   nsRefPtr<ContentParent> contentParent =
     BackgroundParent::GetContentParent(Manager());
 
   nsRefPtr<FactoryOp> actor;
   if (aParams.type() == FactoryRequestParams::TOpenDatabaseRequestParams) {
     actor = new OpenDatabaseOp(this,
                                contentParent.forget(),
                                mOptionalWindowId,
@@ -10443,17 +10437,16 @@ AutoSetProgressHandler::Register(
 FactoryOp::FactoryOp(Factory* aFactory,
                      already_AddRefed<ContentParent> aContentParent,
                      const CommonFactoryRequestParams& aCommonParams,
                      bool aDeleting)
   : mFactory(aFactory)
   , mContentParent(Move(aContentParent))
   , mCommonParams(aCommonParams)
   , mState(State_Initial)
-  , mHasUnlimStoragePerm(false)
   , mEnforcingQuota(true)
   , mDeleting(aDeleting)
   , mBlockedQuotaManager(false)
   , mChromeWriteAccessAllowed(false)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aFactory);
   MOZ_ASSERT(!QuotaClient::IsShuttingDownOnNonMainThread());
@@ -10689,24 +10682,21 @@ FactoryOp::CheckPermission(ContentParent
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   if (NS_WARN_IF(mCommonParams.privateBrowsingMode())) {
     // XXX This is only temporary.
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
-  PersistenceType persistenceType = mCommonParams.metadata().persistenceType();
-
   const PrincipalInfo& principalInfo = mCommonParams.principalInfo();
   MOZ_ASSERT(principalInfo.type() != PrincipalInfo::TNullPrincipalInfo);
 
   if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
     MOZ_ASSERT(mState == State_Initial);
-    MOZ_ASSERT(persistenceType == PERSISTENCE_TYPE_PERSISTENT);
 
     if (aContentParent) {
       // Check to make sure that the child process has access to the database it
       // is accessing.
       NS_NAMED_LITERAL_CSTRING(permissionStringBase,
                                kPermissionStringChromeBase);
       NS_ConvertUTF16toUTF8 databaseName(mCommonParams.metadata().name());
       NS_NAMED_LITERAL_CSTRING(readSuffix, kPermissionStringChromeReadSuffix);
@@ -10745,22 +10735,18 @@ FactoryOp::CheckPermission(ContentParent
       }
 
       mChromeWriteAccessAllowed = canWrite;
     } else {
       mChromeWriteAccessAllowed = true;
     }
 
     if (State_Initial == mState) {
-      QuotaManager::GetInfoForChrome(&mGroup, &mOrigin, nullptr,
-                                     &mHasUnlimStoragePerm);
-
-      mEnforcingQuota =
-        QuotaManager::IsQuotaEnforced(persistenceType, mOrigin,
-                                      mHasUnlimStoragePerm);
+      QuotaManager::GetInfoForChrome(&mGroup, &mOrigin, nullptr, nullptr);
+      mEnforcingQuota = false;
     }
 
     *aPermission = PermissionRequestBase::kPermissionAllowed;
     return NS_OK;
   }
 
   MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
 
@@ -10768,21 +10754,23 @@ FactoryOp::CheckPermission(ContentParent
   nsCOMPtr<nsIPrincipal> principal =
     PrincipalInfoToPrincipal(principalInfo, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   PermissionRequestBase::PermissionValue permission;
 
-  if (persistenceType == PERSISTENCE_TYPE_TEMPORARY) {
+  if (mCommonParams.metadata().persistenceType() ==
+        PERSISTENCE_TYPE_TEMPORARY) {
     // Temporary storage doesn't need to check the permission.
     permission = PermissionRequestBase::kPermissionAllowed;
   } else {
-    MOZ_ASSERT(persistenceType == PERSISTENCE_TYPE_PERSISTENT);
+    MOZ_ASSERT(mCommonParams.metadata().persistenceType() ==
+                 PERSISTENCE_TYPE_PERSISTENT);
 
 #ifdef MOZ_CHILD_PERMISSIONS
     if (aContentParent) {
       if (NS_WARN_IF(!AssertAppPrincipal(aContentParent, principal))) {
         IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
@@ -10798,25 +10786,32 @@ FactoryOp::CheckPermission(ContentParent
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
   }
 
   if (permission != PermissionRequestBase::kPermissionDenied &&
       State_Initial == mState) {
-    rv = QuotaManager::GetInfoFromPrincipal(principal, persistenceType, &mGroup,
-                                            &mOrigin, nullptr,
-                                            &mHasUnlimStoragePerm);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    mEnforcingQuota = QuotaManager::IsQuotaEnforced(persistenceType, mOrigin,
-                                                    mHasUnlimStoragePerm);
+    rv = QuotaManager::GetInfoFromPrincipal(principal, &mGroup, &mOrigin,
+                                            nullptr, nullptr);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  if (permission == PermissionRequestBase::kPermissionAllowed &&
+      mEnforcingQuota)
+  {
+    // If we're running from a window then we should check the quota permission
+    // as well.
+    uint32_t quotaPermission = CheckQuotaHelper::GetQuotaPermission(principal);
+    if (quotaPermission == nsIPermissionManager::ALLOW_ACTION) {
+      mEnforcingQuota = false;
+    }
   }
 
   *aPermission = permission;
   return NS_OK;
 }
 
 nsresult
 FactoryOp::SendVersionChangeMessages(DatabaseActorInfo* aDatabaseActorInfo,
@@ -11211,17 +11206,17 @@ OpenDatabaseOp::DoDatabaseWork()
   MOZ_ASSERT(quotaManager);
 
   nsCOMPtr<nsIFile> dbDirectory;
 
   nsresult rv =
     quotaManager->EnsureOriginIsInitialized(persistenceType,
                                             mGroup,
                                             mOrigin,
-                                            mHasUnlimStoragePerm,
+                                            mEnforcingQuota,
                                             getter_AddRefs(dbDirectory));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = dbDirectory->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -968,20 +968,18 @@ nsresult
 IDBDatabase::GetQuotaInfo(nsACString& aOrigin,
                           PersistenceType* aPersistenceType)
 {
   using mozilla::dom::quota::QuotaManager;
 
   MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
   MOZ_ASSERT(NS_IsMainThread());
 
-  PersistenceType persistenceType = mSpec->metadata().persistenceType();
-
   if (aPersistenceType) {
-    *aPersistenceType = persistenceType;
+    *aPersistenceType = mSpec->metadata().persistenceType();
     MOZ_ASSERT(*aPersistenceType != PERSISTENCE_TYPE_INVALID);
   }
 
   PrincipalInfo* principalInfo = mFactory->GetPrincipalInfo();
   MOZ_ASSERT(principalInfo);
 
   switch (principalInfo->type()) {
     case PrincipalInfo::TNullPrincipalInfo:
@@ -995,17 +993,16 @@ IDBDatabase::GetQuotaInfo(nsACString& aO
       nsresult rv;
       nsCOMPtr<nsIPrincipal> principal =
         PrincipalInfoToPrincipal(*principalInfo, &rv);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       rv = QuotaManager::GetInfoFromPrincipal(principal,
-                                              persistenceType,
                                               nullptr,
                                               &aOrigin,
                                               nullptr,
                                               nullptr);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -478,17 +478,18 @@ IDBFactory::OpenInternal(nsIPrincipal* a
   PersistenceType persistenceType;
   bool persistenceTypeIsExplicit;
 
   if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
     // Chrome privilege always gets persistent storage.
     persistenceType = PERSISTENCE_TYPE_PERSISTENT;
     persistenceTypeIsExplicit = false;
   } else {
-    persistenceType = PersistenceTypeFromStorage(aStorageType);
+    persistenceType =
+      PersistenceTypeFromStorage(aStorageType, PERSISTENCE_TYPE_PERSISTENT);
     persistenceTypeIsExplicit = aStorageType.WasPassed();
   }
 
   DatabaseMetadata& metadata = commonParams.metadata();
   metadata.name() = aName;
   metadata.persistenceType() = persistenceType;
   metadata.persistenceTypeIsExplicit() = persistenceTypeIsExplicit;
 
--- a/dom/indexedDB/IDBMutableFile.cpp
+++ b/dom/indexedDB/IDBMutableFile.cpp
@@ -152,32 +152,31 @@ IDBMutableFile::Create(IDBDatabase* aDat
   PrincipalInfo* principalInfo = aDatabase->Factory()->GetPrincipalInfo();
   MOZ_ASSERT(principalInfo);
 
   nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(*principalInfo);
   if (NS_WARN_IF(!principal)) {
     return nullptr;
   }
 
-  const DatabaseSpec* spec = aDatabase->Spec();
-  MOZ_ASSERT(spec);
-
-  PersistenceType persistenceType = spec->metadata().persistenceType();
-
   nsCString group;
   nsCString origin;
   if (NS_WARN_IF(NS_FAILED(QuotaManager::GetInfoFromPrincipal(principal,
-                                                              persistenceType,
                                                               &group,
                                                               &origin,
                                                               nullptr,
                                                               nullptr)))) {
     return nullptr;
   }
 
+  const DatabaseSpec* spec = aDatabase->Spec();
+  MOZ_ASSERT(spec);
+
+  PersistenceType persistenceType = spec->metadata().persistenceType();
+
   nsCString storageId;
   QuotaManager::GetStorageId(persistenceType,
                              origin,
                              Client::IDB,
                              aDatabase->Name(),
                              storageId);
 
   nsCOMPtr<nsIFile> file = GetFileFor(fileInfo);
--- a/dom/indexedDB/moz.build
+++ b/dom/indexedDB/moz.build
@@ -88,12 +88,13 @@ include('/ipc/chromium/chromium-config.m
 
 FINAL_LIBRARY = 'xul'
 
 FAIL_ON_WARNINGS = True
 
 LOCAL_INCLUDES += [
     '/db/sqlite3/src',
     '/dom/base',
+    '/dom/quota',
     '/dom/storage',
     '/ipc/glue',
     '/xpcom/build',
 ]
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -143,19 +143,17 @@ skip-if = (buildapp == 'b2g' && toolkit 
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_cursors.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_deleteDatabase.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_deleteDatabase_interactions.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_disabled_quota_prompt.html]
-# Test temporarily disabled.
-skip-if = true
-# skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
+skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_error_events_abort_transactions.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_event_propagation.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_event_source.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_exceptions_in_events.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
--- a/dom/indexedDB/test/unit/test_temporary_storage.js
+++ b/dom/indexedDB/test/unit/test_temporary_storage.js
@@ -1,13 +1,15 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+Components.utils.importGlobalProperties(['Blob']);
+
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
 
   const urls = [
     { url: "http://www.alpha.com",        flags: [true, true, true, true] },
@@ -30,30 +32,27 @@ function testSteps()
     { url: "http://www.marie.org",        flags: [true, true, true, true] },
     { url: "http://www.john.org",         flags: [true, true, true, true] },
     { url: "http://www.ema.org",          flags: [true, true, true, true] },
     { url: "http://www.trigger.com",      flags: [false, true, true, true] }
   ];
   const lastIndex = urls.length - 1;
   const lastUrl = urls[lastIndex].url;
 
-  const openDBOptions = [
-    { version: 1, storage: "temporary" },
-    { version: 1 }
-  ];
-
   let quotaManager =
     Components.classes["@mozilla.org/dom/quota/manager;1"]
               .getService(Components.interfaces.nsIQuotaManager);
 
   let ioService = Components.classes["@mozilla.org/network/io-service;1"]
                             .getService(Components.interfaces.nsIIOService);
 
   let dbSize = 0;
 
+  let databases = [];
+
   function setLimit(limit) {
     if (limit) {
       SpecialPowers.setIntPref("dom.quotaManager.temporaryStorage.fixedLimit",
                                limit);
       return;
     }
     SpecialPowers.clearUserPref("dom.quotaManager.temporaryStorage.fixedLimit");
   }
@@ -108,127 +107,127 @@ function testSteps()
                                            { storage: "temporary" });
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   let event = yield undefined;
 
   getUsageForUrl(lastUrl, grabUsageAndContinueHandler);
   dbSize = yield undefined;
 
-  for (let options of openDBOptions) {
-    setLimit(lastIndex * dbSize / 1024);
-    quotaManager.clear();
-
-    info("Stage 1");
-
-    let databases = [];
-    for (let i = 0; i < lastIndex; i++) {
-      let data = urls[i];
-
-      info("Opening database for " + data.url);
+  setLimit(lastIndex * dbSize / 1024);
+  quotaManager.clear();
 
-      request = indexedDB.openForPrincipal(getPrincipal(data.url), name,
-                                           options);
-      request.onerror = errorHandler;
-      request.onupgradeneeded = grabEventAndContinueHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
-
-      is(event.type, "upgradeneeded", "Got correct event type");
-
-      let db = event.target.result;
-      db.createObjectStore("foo", { });
-
-      event = yield undefined;
-
-      is(event.type, "success", "Got correct event type");
+  info("Stage 1");
 
-      databases.push(event.target.result);
-    }
-
-    request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name, options);
-    request.addEventListener("error", new ExpectError("QuotaExceededError"));
-    request.onsuccess = unexpectedSuccessHandler;
-    event = yield undefined;
-
-    checkUsage(1);
-    yield undefined;
-
-    info("Stage 2");
-
-    for (let i = 1; i < urls.length; i++) {
-      databases[i] = null;
+  for (let i = 0; i < lastIndex; i++) {
+    let data = urls[i];
 
-      scheduleGC();
-      yield undefined;
+    info("Opening database for " + data.url);
 
-      // The origin access time is set to the current system time when the first
-      // database for an origin is registered or the last one is unregistered.
-      // The registration happens when the database object is being created and
-      // the unregistration when it is unlinked/garbage collected.
-      // Some older windows systems have the system time limited to a maximum
-      // resolution of 10 or 15 milliseconds, so without a pause here we would
-      // end up with origins with the same access time which would cause random
-      // failures.
-      setTimeout(function() { testGenerator.next(); }, 20);
-      yield undefined;
-    }
-
-    request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name, options);
+    request = indexedDB.openForPrincipal(getPrincipal(data.url), name,
+                                         { storage: "temporary" });
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     request.onsuccess = grabEventAndContinueHandler;
     event = yield undefined;
 
     is(event.type, "upgradeneeded", "Got correct event type");
 
     let db = event.target.result;
     db.createObjectStore("foo", { });
 
     event = yield undefined;
 
     is(event.type, "success", "Got correct event type");
 
-    checkUsage(2);
+    databases.push(event.target.result);
+  }
+
+  request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name,
+                                       { storage: "temporary" });
+  request.addEventListener("error", new ExpectError("QuotaExceededError"));
+  request.onsuccess = unexpectedSuccessHandler;
+  event = yield undefined;
+
+  checkUsage(1);
+  yield undefined;
+
+  info("Stage 2");
+
+  for (let i = 1; i < urls.length; i++) {
+    databases[i] = null;
+
+    scheduleGC();
     yield undefined;
 
-    info("Stage 3");
-
-    setLimit(14 * dbSize / 1024);
-    quotaManager.reset();
-
-    request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name, options);
-    request.onerror = errorHandler;
-    request.onsuccess = grabEventAndContinueHandler;
-    event = yield undefined;
-
-    is(event.type, "success", "Got correct event type");
-
-    db = event.target.result;
-
-    checkUsage(3);
-    yield undefined;
-
-    info("Stage 4");
-
-    let trans = db.transaction(["foo"], "readwrite");
-
-    let blob = new Blob(["bar"]);
-    request = trans.objectStore("foo").add(blob, 42);
-    request.onerror = errorHandler;
-    request.onsuccess = grabEventAndContinueHandler;
-    event = yield undefined;
-
-    trans.oncomplete = grabEventAndContinueHandler;
-    event = yield undefined;
-
-    checkUsage(4);
+    // The origin access time is set to the current system time when the first
+    // database for an origin is registered or the last one is unregistered.
+    // The registration happens when the database object is being created and
+    // the unregistration when it is unlinked/garbage collected.
+    // Some older windows systems have the system time limited to a maximum
+    // resolution of 10 or 15 milliseconds, so without a pause here we would
+    // end up with origins with the same access time which would cause random
+    // failures.
+    setTimeout(function() { testGenerator.next(); }, 20);
     yield undefined;
   }
 
+  request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name,
+                                       { storage: "temporary" });
+  request.onerror = errorHandler;
+  request.onupgradeneeded = grabEventAndContinueHandler;
+  request.onsuccess = grabEventAndContinueHandler;
+  event = yield undefined;
+
+  is(event.type, "upgradeneeded", "Got correct event type");
+
+  let db = event.target.result;
+  db.createObjectStore("foo", { });
+
+  event = yield undefined;
+
+  is(event.type, "success", "Got correct event type");
+
+  checkUsage(2);
+  yield undefined;
+
+  info("Stage 3");
+
+  setLimit(14 * dbSize / 1024);
+  quotaManager.reset();
+
+  request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name,
+                                       { storage: "temporary" });
+  request.onerror = errorHandler;
+  request.onsuccess = grabEventAndContinueHandler;
+  event = yield undefined;
+
+  is(event.type, "success", "Got correct event type");
+
+  db = event.target.result;
+
+  checkUsage(3);
+  yield undefined;
+
+  info("Stage 4");
+
+  let trans = db.transaction(["foo"], "readwrite");
+
+  let blob = new Blob(["bar"]);
+  request = trans.objectStore("foo").add(blob, 42);
+  request.onerror = errorHandler;
+  request.onsuccess = grabEventAndContinueHandler;
+  event = yield undefined;
+
+  trans.oncomplete = grabEventAndContinueHandler;
+  event = yield undefined;
+
+  checkUsage(4);
+  yield undefined;
+
   info("Cleanup");
 
   setLimit();
   quotaManager.reset();
 
   SpecialPowers.setBoolPref("dom.quotaManager.testing", testingEnabled);
 
   finishTest();
--- a/dom/quota/OriginCollection.h
+++ b/dom/quota/OriginCollection.h
@@ -24,19 +24,18 @@ public:
   {
     return mPatterns.Contains(aPattern);
   }
 
   void
   AddPattern(const nsACString& aPattern)
   {
     MOZ_ASSERT(!mOrigins.Count());
-    if (!ContainsPattern(aPattern)) {
-      mPatterns.AppendElement(aPattern);
-    }
+    MOZ_ASSERT(!ContainsPattern(aPattern));
+    mPatterns.AppendElement(aPattern);
   }
 
   bool
   ContainsOrigin(const nsACString& aOrigin)
   {
     for (uint32_t index = 0; index < mPatterns.Length(); index++) {
       if (PatternMatchesOrigin(mPatterns[index], aOrigin)) {
         return true;
@@ -44,19 +43,18 @@ public:
     }
 
     return mOrigins.GetEntry(aOrigin);
   }
 
   void
   AddOrigin(const nsACString& aOrigin)
   {
-    if (!ContainsOrigin(aOrigin)) {
-      mOrigins.PutEntry(aOrigin);
-    }
+    MOZ_ASSERT(!ContainsOrigin(aOrigin));
+    mOrigins.PutEntry(aOrigin);
   }
 
 private:
   nsTArray<nsCString> mPatterns;
   nsTHashtable<nsCStringHashKey> mOrigins;
 };
 
 END_QUOTA_NAMESPACE
--- a/dom/quota/PersistenceType.h
+++ b/dom/quota/PersistenceType.h
@@ -77,31 +77,21 @@ NullablePersistenceTypeFromText(const ns
 
 inline mozilla::dom::StorageType
 PersistenceTypeToStorage(PersistenceType aPersistenceType)
 {
   return mozilla::dom::StorageType(static_cast<int>(aPersistenceType));
 }
 
 inline PersistenceType
-PersistenceTypeFromStorage(const Optional<mozilla::dom::StorageType>& aStorage)
+PersistenceTypeFromStorage(const Optional<mozilla::dom::StorageType>& aStorage,
+                           PersistenceType aDefaultPersistenceType)
 {
   if (aStorage.WasPassed()) {
     return PersistenceType(static_cast<int>(aStorage.Value()));
   }
 
-  return PERSISTENCE_TYPE_PERSISTENT;
-}
-
-inline PersistenceType
-ComplementaryPersistenceType(PersistenceType aPersistenceType)
-{
-  if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
-    return PERSISTENCE_TYPE_TEMPORARY;
-  }
-
-  MOZ_ASSERT(aPersistenceType == PERSISTENCE_TYPE_TEMPORARY);
-  return PERSISTENCE_TYPE_PERSISTENT;
+  return aDefaultPersistenceType;
 }
 
 END_QUOTA_NAMESPACE
 
 #endif // mozilla_dom_quota_persistencetype_h__
--- a/dom/quota/QuotaManager.cpp
+++ b/dom/quota/QuotaManager.cpp
@@ -7,17 +7,16 @@
 #include "QuotaManager.h"
 
 #include "mozIApplicationClearPrivateDataParams.h"
 #include "nsIBinaryInputStream.h"
 #include "nsIBinaryOutputStream.h"
 #include "nsIFile.h"
 #include "nsIObserverService.h"
 #include "nsIOfflineStorage.h"
-#include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
 #include "nsIQuotaRequest.h"
 #include "nsIRunnable.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsITimer.h"
 #include "nsIURI.h"
@@ -37,17 +36,16 @@
 #include "mozilla/Services.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsComponentManagerUtils.h"
 #include "nsAboutProtocolUtils.h"
 #include "nsContentUtils.h"
 #include "nsCRTGlue.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsNetUtil.h"
-#include "nsPrintfCString.h"
 #include "nsScriptSecurityManager.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "xpcpublic.h"
 
 #include "AcquireListener.h"
 #include "CheckQuotaHelper.h"
 #include "OriginCollection.h"
@@ -85,17 +83,16 @@
 
 #define PERMISSION_DEFAUT_PERSISTENT_STORAGE "default-persistent-storage"
 
 #define KB * 1024ULL
 #define MB * 1024ULL KB
 #define GB * 1024ULL MB
 
 USING_QUOTA_NAMESPACE
-using namespace mozilla;
 using namespace mozilla::dom;
 using mozilla::dom::FileService;
 
 static_assert(
   static_cast<uint32_t>(StorageType::Persistent) ==
   static_cast<uint32_t>(PERSISTENCE_TYPE_PERSISTENT),
   "Enum values should match.");
 
@@ -275,18 +272,17 @@ class AsyncUsageRunnable MOZ_FINAL : pub
   };
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIQUOTAREQUEST
 
   AsyncUsageRunnable(uint32_t aAppId,
                      bool aInMozBrowserOnly,
-                     const nsACString& aPersistentGroup,
-                     const nsACString& aTemporaryGroup,
+                     const nsACString& aGroup,
                      const OriginOrPatternString& aOrigin,
                      nsIURI* aURI,
                      nsIUsageCallback* aCallback);
 
   NS_IMETHOD
   Run();
 
   void
@@ -320,18 +316,17 @@ private:
 
   nsresult
   AddToUsage(QuotaManager* aQuotaManager,
              PersistenceType aPersistenceType);
 
   nsCOMPtr<nsIURI> mURI;
   nsCOMPtr<nsIUsageCallback> mCallback;
   uint32_t mAppId;
-  nsCString mPersistentGroup;
-  nsCString mTemporaryGroup;
+  nsCString mGroup;
   OriginOrPatternString mOrigin;
   CallbackState mCallbackState;
   bool mInMozBrowserOnly;
 };
 
 class ResetOrClearRunnable MOZ_FINAL : public nsRunnable,
                                        public AcquireListener
 {
@@ -417,17 +412,17 @@ class FinalizeOriginEvictionRunnable MOZ
     // Running on the IO thread.
     IO,
 
     // Running on the main thread after IO work is done.
     Complete
   };
 
 public:
-  explicit FinalizeOriginEvictionRunnable(nsTArray<OriginParams>& aOrigins)
+  explicit FinalizeOriginEvictionRunnable(nsTArray<nsCString>& aOrigins)
   : mCallbackState(Pending)
   {
     mOrigins.SwapElements(aOrigins);
   }
 
   NS_IMETHOD
   Run();
 
@@ -452,17 +447,17 @@ public:
   nsresult
   Dispatch();
 
   nsresult
   RunImmediately();
 
 private:
   CallbackState mCallbackState;
-  nsTArray<OriginParams> mOrigins;
+  nsTArray<nsCString> mOrigins;
 };
 
 bool
 IsOnIOThread()
 {
   QuotaManager* quotaManager = QuotaManager::Get();
   NS_ASSERTION(quotaManager, "Must have a manager here!");
 
@@ -557,53 +552,46 @@ public:
 
 private:
   bool mBusy;
 };
 
 class SaveOriginAccessTimeRunnable MOZ_FINAL : public nsRunnable
 {
 public:
-  SaveOriginAccessTimeRunnable(PersistenceType aPersistenceType,
-                               const nsACString& aOrigin,
-                               int64_t aTimestamp)
-  : mPersistenceType(aPersistenceType), mOrigin(aOrigin), mTimestamp(aTimestamp)
+  SaveOriginAccessTimeRunnable(const nsACString& aOrigin, int64_t aTimestamp)
+  : mOrigin(aOrigin), mTimestamp(aTimestamp)
   { }
 
   NS_IMETHOD
   Run();
 
 private:
-  PersistenceType mPersistenceType;
   nsCString mOrigin;
   int64_t mTimestamp;
 };
 
 struct MOZ_STACK_CLASS RemoveQuotaInfo
 {
   RemoveQuotaInfo(PersistenceType aPersistenceType, const nsACString& aPattern)
   : persistenceType(aPersistenceType), pattern(aPattern)
   { }
 
   PersistenceType persistenceType;
   nsCString pattern;
 };
 
 struct MOZ_STACK_CLASS InactiveOriginsInfo
 {
-  InactiveOriginsInfo(OriginCollection& aPersistentCollection,
-                      OriginCollection& aTemporaryCollection,
+  InactiveOriginsInfo(OriginCollection& aCollection,
                       nsTArray<OriginInfo*>& aOrigins)
-  : persistentCollection(aPersistentCollection),
-    temporaryCollection(aTemporaryCollection),
-    origins(aOrigins)
+  : collection(aCollection), origins(aOrigins)
   { }
 
-  OriginCollection& persistentCollection;
-  OriginCollection& temporaryCollection;
+  OriginCollection& collection;
   nsTArray<OriginInfo*>& origins;
 };
 
 bool
 IsMainProcess()
 {
   return XRE_GetProcessType() == GeckoProcessType_Default;
 }
@@ -645,18 +633,36 @@ EnsureDirectory(nsIFile* aDirectory, boo
 
     *aCreated = true;
   }
 
   return NS_OK;
 }
 
 nsresult
-GetDirectoryMetadataOutputStream(nsIFile* aDirectory, bool aUpdate,
-                                 nsIBinaryOutputStream** aStream)
+CreateDirectoryUpgradeStamp(nsIFile* aDirectory)
+{
+  AssertIsOnIOThread();
+
+  nsCOMPtr<nsIFile> metadataFile;
+  nsresult rv = aDirectory->Clone(getter_AddRefs(metadataFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = metadataFile->Append(NS_LITERAL_STRING(METADATA_FILE_NAME));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = metadataFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+nsresult
+GetDirectoryMetadataStream(nsIFile* aDirectory, bool aUpdate,
+                           nsIBinaryOutputStream** aStream)
 {
   AssertIsOnIOThread();
 
   nsCOMPtr<nsIFile> metadataFile;
   nsresult rv = aDirectory->Clone(getter_AddRefs(metadataFile));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = metadataFile->Append(NS_LITERAL_STRING(METADATA_FILE_NAME));
@@ -700,17 +706,17 @@ GetDirectoryMetadataOutputStream(nsIFile
 nsresult
 CreateDirectoryMetadata(nsIFile* aDirectory, int64_t aTimestamp,
                         const nsACString& aGroup, const nsACString& aOrigin)
 {
   AssertIsOnIOThread();
 
   nsCOMPtr<nsIBinaryOutputStream> stream;
   nsresult rv =
-    GetDirectoryMetadataOutputStream(aDirectory, false, getter_AddRefs(stream));
+    GetDirectoryMetadataStream(aDirectory, false, getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ASSERTION(stream, "This shouldn't be null!");
 
   rv = stream->Write64(aTimestamp);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = stream->WriteStringZ(PromiseFlatCString(aGroup).get());
@@ -718,94 +724,43 @@ CreateDirectoryMetadata(nsIFile* aDirect
 
   rv = stream->WriteStringZ(PromiseFlatCString(aOrigin).get());
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-CreateDirectoryMetadataLastModifiedTime(nsIFile* aDirectory, int64_t aTimestamp)
+GetDirectoryMetadata(nsIFile* aDirectory, int64_t* aTimestamp,
+                     nsACString& aGroup, nsACString& aOrigin)
 {
   AssertIsOnIOThread();
 
-  nsCOMPtr<nsIBinaryOutputStream> stream;
-  nsresult rv =
-    GetDirectoryMetadataOutputStream(aDirectory, false, getter_AddRefs(stream));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  MOZ_ASSERT(stream);
-
-  rv = stream->Write64(aTimestamp);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  return NS_OK;
-}
-
-nsresult
-GetDirectoryMetadataInputStream(nsIFile* aDirectory,
-                                bool aClone,
-                                nsIBinaryInputStream** aStream)
-{
-  AssertIsOnIOThread();
-  MOZ_ASSERT(aDirectory);
-  MOZ_ASSERT(aStream);
-
-  nsresult rv;
-
   nsCOMPtr<nsIFile> metadataFile;
-
-  if (aClone) {
-    rv = aDirectory->Clone(getter_AddRefs(metadataFile));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = metadataFile->Append(NS_LITERAL_STRING(METADATA_FILE_NAME));
-    NS_ENSURE_SUCCESS(rv, rv);
-  } else {
-    metadataFile = aDirectory;
-  }
+  nsresult rv = aDirectory->Clone(getter_AddRefs(metadataFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = metadataFile->Append(NS_LITERAL_STRING(METADATA_FILE_NAME));
+  NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIInputStream> stream;
   rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), metadataFile);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIInputStream> bufferedStream;
   rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream), stream, 512);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIBinaryInputStream> binaryStream =
     do_CreateInstance("@mozilla.org/binaryinputstream;1");
   NS_ENSURE_TRUE(binaryStream, NS_ERROR_FAILURE);
 
   rv = binaryStream->SetInputStream(bufferedStream);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  binaryStream.forget(aStream);
-  return NS_OK;
-}
-
-nsresult
-GetDirectoryMetadata(nsIFile* aDirectory,
-                     int64_t* aTimestamp,
-                     nsACString& aGroup,
-                     nsACString& aOrigin)
-{
-  AssertIsOnIOThread();
-  MOZ_ASSERT(aDirectory);
-  MOZ_ASSERT(aTimestamp);
-
-  nsCOMPtr<nsIBinaryInputStream> binaryStream;
-  nsresult rv = GetDirectoryMetadataInputStream(aDirectory, true,
-                                                getter_AddRefs(binaryStream));
-  NS_ENSURE_SUCCESS(rv, rv);
-
   uint64_t timestamp;
   rv = binaryStream->Read64(&timestamp);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCString group;
   rv = binaryStream->ReadCString(group);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -815,113 +770,16 @@ GetDirectoryMetadata(nsIFile* aDirectory
 
   *aTimestamp = timestamp;
   aGroup = group;
   aOrigin = origin;
   return NS_OK;
 }
 
 nsresult
-GetDirectoryMetadataLastModifiedTime(nsIFile* aDirectory, int64_t* aTimestamp)
-{
-  AssertIsOnIOThread();
-  MOZ_ASSERT(aDirectory);
-  MOZ_ASSERT(aTimestamp);
-
-  nsresult rv;
-
-#ifdef DEBUG
-  nsCOMPtr<nsIFile> parentDirectory;
-  rv = aDirectory->GetParent(getter_AddRefs(parentDirectory));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  nsString path;
-  rv = parentDirectory->GetPath(path);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  QuotaManager* quotaManager = QuotaManager::Get();
-  MOZ_ASSERT(quotaManager);
-
-  MOZ_ASSERT(path == quotaManager->GetStoragePath(PERSISTENCE_TYPE_PERSISTENT));
-#endif
-
-  nsCOMPtr<nsIFile> metadataFile;
-  rv = aDirectory->Clone(getter_AddRefs(metadataFile));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = metadataFile->Append(NS_LITERAL_STRING(METADATA_FILE_NAME));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  bool exists;
-  rv = metadataFile->Exists(&exists);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-  if (NS_WARN_IF(!exists)) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  bool isDirectory;
-  rv = metadataFile->IsDirectory(&isDirectory);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-  if (NS_WARN_IF(isDirectory)) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  int64_t fileSize;
-  rv = metadataFile->GetFileSize(&fileSize);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  // XXX Since we don't have regular metadata files for persistent storage yet,
-  //     we have to use a temporary hack.
-  //     Load origin access time from the metadata file, if we alredy saved it
-  //     to it. If the file size doesn't match a metadata file with saved origin
-  //     access time, get the last modiefied time of the metadata file and use
-  //     it as origin access time.
-  if (fileSize == sizeof(uint64_t)) {
-    nsCOMPtr<nsIBinaryInputStream> binaryStream;
-    rv = GetDirectoryMetadataInputStream(metadataFile, false,
-                                         getter_AddRefs(binaryStream));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    uint64_t timestamp;
-    rv = binaryStream->Read64(&timestamp);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    *aTimestamp = timestamp;
-    return NS_OK;
-  }
-
-  int64_t timestamp;
-  rv = metadataFile->GetLastModifiedTime(&timestamp);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  *aTimestamp = timestamp;
-  return NS_OK;
-}
-
-nsresult
 MaybeUpgradeOriginDirectory(nsIFile* aDirectory)
 {
   AssertIsOnIOThread();
   NS_ASSERTION(aDirectory, "Null pointer!");
 
   nsCOMPtr<nsIFile> metadataFile;
   nsresult rv = aDirectory->Clone(getter_AddRefs(metadataFile));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1207,33 +1065,33 @@ void
 QuotaManager::InitQuotaForOrigin(PersistenceType aPersistenceType,
                                  const nsACString& aGroup,
                                  const nsACString& aOrigin,
                                  uint64_t aLimitBytes,
                                  uint64_t aUsageBytes,
                                  int64_t aAccessTime)
 {
   AssertIsOnIOThread();
-  MOZ_ASSERT_IF(IsTreatedAsPersistent(aPersistenceType, aOrigin),
-                aLimitBytes > 0);
-  MOZ_ASSERT_IF(IsTreatedAsPersistent(aPersistenceType, aOrigin),
-                aUsageBytes <= aLimitBytes);
+  MOZ_ASSERT(aLimitBytes > 0 ||
+             aPersistenceType == PERSISTENCE_TYPE_TEMPORARY);
+  MOZ_ASSERT(aUsageBytes <= aLimitBytes ||
+             aPersistenceType == PERSISTENCE_TYPE_TEMPORARY);
 
   MutexAutoLock lock(mQuotaMutex);
 
   GroupInfoPair* pair;
   if (!mGroupInfoPairs.Get(aGroup, &pair)) {
     pair = new GroupInfoPair();
     mGroupInfoPairs.Put(aGroup, pair);
     // The hashtable is now responsible to delete the GroupInfoPair.
   }
 
   nsRefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
   if (!groupInfo) {
-    groupInfo = new GroupInfo(pair, aPersistenceType, aGroup);
+    groupInfo = new GroupInfo(aPersistenceType, aGroup);
     pair->LockedSetGroupInfo(groupInfo);
   }
 
   nsRefPtr<OriginInfo> originInfo =
     new OriginInfo(groupInfo, aOrigin, aLimitBytes, aUsageBytes, aAccessTime);
   groupInfo->LockedAddOriginInfo(originInfo);
 }
 
@@ -1272,48 +1130,48 @@ QuotaManager::UpdateOriginAccessTime(Per
 
   MutexAutoLock lock(mQuotaMutex);
 
   GroupInfoPair* pair;
   if (!mGroupInfoPairs.Get(aGroup, &pair)) {
     return;
   }
 
-  nsRefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
+  nsRefPtr<GroupInfo> groupInfo =
+    pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
   if (!groupInfo) {
     return;
   }
 
   nsRefPtr<OriginInfo> originInfo = groupInfo->LockedGetOriginInfo(aOrigin);
   if (originInfo) {
     int64_t timestamp = PR_Now();
     originInfo->LockedUpdateAccessTime(timestamp);
 
+    if (!groupInfo->IsForTemporaryStorage()) {
+      return;
+    }
+
     MutexAutoUnlock autoUnlock(mQuotaMutex);
 
-    SaveOriginAccessTime(aPersistenceType, aOrigin, timestamp);
+    SaveOriginAccessTime(aOrigin, timestamp);
   }
 }
 
 // static
 PLDHashOperator
 QuotaManager::RemoveQuotaCallback(const nsACString& aKey,
                                   nsAutoPtr<GroupInfoPair>& aValue,
                                   void* aUserArg)
 {
   NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
   NS_ASSERTION(aValue, "Null pointer!");
 
   nsRefPtr<GroupInfo> groupInfo =
-    aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_PERSISTENT);
-  if (groupInfo) {
-    groupInfo->LockedRemoveOriginInfos();
-  }
-
-  groupInfo = aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
+    aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
   if (groupInfo) {
     groupInfo->LockedRemoveOriginInfos();
   }
 
   return PL_DHASH_REMOVE;
 }
 
 void
@@ -1323,54 +1181,50 @@ QuotaManager::RemoveQuota()
 
   mGroupInfoPairs.Enumerate(RemoveQuotaCallback, nullptr);
 
   NS_ASSERTION(mTemporaryStorageUsage == 0, "Should be zero!");
 }
 
 // static
 PLDHashOperator
-QuotaManager::RemoveQuotaForTemporaryStorageCallback(
+QuotaManager::RemoveQuotaForPersistenceTypeCallback(
                                                const nsACString& aKey,
                                                nsAutoPtr<GroupInfoPair>& aValue,
                                                void* aUserArg)
 {
   NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
   NS_ASSERTION(aValue, "Null pointer!");
-
-  nsRefPtr<GroupInfo> groupInfo =
-    aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_PERSISTENT);
-  if (groupInfo) {
-    groupInfo->LockedRemoveTemporaryOriginInfos();
-
-    if (!groupInfo->LockedHasOriginInfos()) {
-      aValue->LockedClearGroupInfo(PERSISTENCE_TYPE_PERSISTENT);
+  NS_ASSERTION(aUserArg, "Null pointer!");
+
+  PersistenceType& persistenceType = *static_cast<PersistenceType*>(aUserArg);
+
+  if (persistenceType == PERSISTENCE_TYPE_TEMPORARY) {
+    nsRefPtr<GroupInfo> groupInfo =
+      aValue->LockedGetGroupInfo(persistenceType);
+    if (groupInfo) {
+      groupInfo->LockedRemoveOriginInfos();
     }
   }
 
-  groupInfo = aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
-  if (groupInfo) {
-    groupInfo->LockedRemoveTemporaryOriginInfos();
-
-    if (!groupInfo->LockedHasOriginInfos()) {
-      aValue->LockedClearGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
-    }
-  }
+  aValue->LockedClearGroupInfo(persistenceType);
 
   return aValue->LockedHasGroupInfos() ? PL_DHASH_NEXT : PL_DHASH_REMOVE;
 }
 
 void
-QuotaManager::RemoveQuotaForTemporaryStorage()
+QuotaManager::RemoveQuotaForPersistenceType(PersistenceType aPersistenceType)
 {
   MutexAutoLock lock(mQuotaMutex);
 
-  mGroupInfoPairs.Enumerate(RemoveQuotaForTemporaryStorageCallback, nullptr);
-
-  NS_ASSERTION(mTemporaryStorageUsage == 0, "Should be zero!");
+  mGroupInfoPairs.Enumerate(RemoveQuotaForPersistenceTypeCallback,
+                            &aPersistenceType);
+
+  NS_ASSERTION(aPersistenceType == PERSISTENCE_TYPE_PERSISTENT ||
+               mTemporaryStorageUsage == 0, "Should be zero!");
 }
 
 // static
 PLDHashOperator
 QuotaManager::RemoveQuotaForPatternCallback(const nsACString& aKey,
                                             nsAutoPtr<GroupInfoPair>& aValue,
                                             void* aUserArg)
 {
@@ -1508,63 +1362,44 @@ QuotaManager::RegisterStorage(nsIOffline
   }
 
   // Add this storage to its origin info if it exists, create it otherwise.
   const nsACString& origin = aStorage->Origin();
   ArrayCluster<nsIOfflineStorage*>* cluster;
   if (!mLiveStorages.Get(origin, &cluster)) {
     cluster = new ArrayCluster<nsIOfflineStorage*>();
     mLiveStorages.Put(origin, cluster);
-  }
-  (*cluster)[aStorage->GetClient()->GetType()].AppendElement(aStorage);
-
-  LiveStorageTable& liveStorageTable = GetLiveStorageTable(aStorage->Type());
-
-  nsTArray<nsIOfflineStorage*>* array;
-  if (!liveStorageTable.Get(origin, &array)) {
-    array = new nsTArray<nsIOfflineStorage*>();
-    liveStorageTable.Put(origin, array);
 
     UpdateOriginAccessTime(aStorage->Type(), aStorage->Group(), origin);
   }
-  array->AppendElement(aStorage);
+  (*cluster)[aStorage->GetClient()->GetType()].AppendElement(aStorage);
 
   return true;
 }
 
 void
 QuotaManager::UnregisterStorage(nsIOfflineStorage* aStorage)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aStorage, "Null pointer!");
 
   // Remove this storage from its origin array, maybe remove the array if it
   // is then empty.
   const nsACString& origin = aStorage->Origin();
-
   ArrayCluster<nsIOfflineStorage*>* cluster;
-  MOZ_ALWAYS_TRUE(mLiveStorages.Get(origin, &cluster));
-
-  MOZ_ALWAYS_TRUE(
-    (*cluster)[aStorage->GetClient()->GetType()].RemoveElement(aStorage));
-  if (cluster->IsEmpty()) {
-    mLiveStorages.Remove(origin);
+  if (mLiveStorages.Get(origin, &cluster) &&
+      (*cluster)[aStorage->GetClient()->GetType()].RemoveElement(aStorage)) {
+    if (cluster->IsEmpty()) {
+      mLiveStorages.Remove(origin);
+
+      UpdateOriginAccessTime(aStorage->Type(), aStorage->Group(), origin);
+    }
+    return;
   }
-
-  LiveStorageTable& liveStorageTable = GetLiveStorageTable(aStorage->Type());
-
-  nsTArray<nsIOfflineStorage*>* array;
-  MOZ_ALWAYS_TRUE(liveStorageTable.Get(origin, &array));
-
-  MOZ_ALWAYS_TRUE(array->RemoveElement(aStorage));
-  if (array->IsEmpty()) {
-    liveStorageTable.Remove(origin);
-
-    UpdateOriginAccessTime(aStorage->Type(), aStorage->Group(), origin);
-  }
+  NS_ERROR("Didn't know anything about this storage!");
 }
 
 void
 QuotaManager::OnStorageClosed(nsIOfflineStorage* aStorage)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aStorage, "Null pointer!");
 
@@ -1816,141 +1651,37 @@ QuotaManager::GetDirectoryForOrigin(Pers
   rv = directory->Append(NS_ConvertASCIItoUTF16(originSanitized));
   NS_ENSURE_SUCCESS(rv, rv);
 
   directory.forget(aDirectory);
   return NS_OK;
 }
 
 nsresult
-QuotaManager::InitializeRepository(PersistenceType aPersistenceType)
-{
-  nsresult rv;
-
-  nsCOMPtr<nsIFile> directory =
-    do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = directory->InitWithPath(GetStoragePath(aPersistenceType));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  bool created;
-  rv = EnsureDirectory(directory, &created);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  nsCOMPtr<nsISimpleEnumerator> entries;
-  rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  bool hasMore;
-  while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
-    nsCOMPtr<nsISupports> entry;
-    rv = entries->GetNext(getter_AddRefs(entry));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    nsCOMPtr<nsIFile> childDirectory = do_QueryInterface(entry);
-    MOZ_ASSERT(childDirectory);
-
-    nsString leafName;
-    rv = childDirectory->GetLeafName(leafName);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    bool isDirectory;
-    rv = childDirectory->IsDirectory(&isDirectory);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    if (!isDirectory) {
-      if (leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
-        continue;
-      }
-
-      nsPrintfCString message("Something (%s) in the repository that doesn't "
-                              "belong!", NS_ConvertUTF16toUTF8(leafName).get());
-      NS_WARNING(message.get());
-      return NS_ERROR_UNEXPECTED;
-    }
-
-    int64_t timestamp;
-    nsCString group;
-    nsCString origin;
-
-    // XXX This is temporary, we don't have real .metadata files for persistent
-    //     storage yet.
-    if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
-      rv = GetDirectoryMetadataLastModifiedTime(childDirectory, &timestamp);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
-      }
-
-      origin = NS_ConvertUTF16toUTF8(leafName);
-      group = origin;
-    } else {
-      rv = GetDirectoryMetadata(childDirectory, &timestamp, group, origin);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
-      }
-
-      SanitizeOriginString(origin);
-    }
-
-    if (IsTreatedAsPersistent(aPersistenceType, origin)) {
-      continue;
-    }
-
-    rv = InitializeOrigin(aPersistenceType, group, origin, false, timestamp,
-                          childDirectory);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-  }
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  return NS_OK;
-}
-
-nsresult
 QuotaManager::InitializeOrigin(PersistenceType aPersistenceType,
                                const nsACString& aGroup,
                                const nsACString& aOrigin,
-                               bool aHasUnlimStoragePerm,
+                               bool aTrackQuota,
                                int64_t aAccessTime,
                                nsIFile* aDirectory)
 {
   AssertIsOnIOThread();
 
   nsresult rv;
 
-  if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
+  bool temporaryStorage = aPersistenceType == PERSISTENCE_TYPE_TEMPORARY;
+  if (!temporaryStorage) {
     rv = MaybeUpgradeOriginDirectory(aDirectory);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  bool trackQuota =
-    IsQuotaEnforced(aPersistenceType, aOrigin, aHasUnlimStoragePerm);
-
   // We need to initialize directories of all clients if they exists and also
   // get the total usage to initialize the quota.
   nsAutoPtr<UsageInfo> usageInfo;
-  if (trackQuota) {
+  if (aTrackQuota) {
     usageInfo = new UsageInfo();
   }
 
   nsCOMPtr<nsISimpleEnumerator> entries;
   rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasMore;
@@ -1987,21 +1718,21 @@ QuotaManager::InitializeOrigin(Persisten
       return NS_ERROR_UNEXPECTED;
     }
 
     rv = mClients[clientType]->InitOrigin(aPersistenceType, aGroup, aOrigin,
                                           usageInfo);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  if (trackQuota) {
+  if (aTrackQuota) {
     uint64_t quotaMaxBytes;
     uint64_t totalUsageBytes = usageInfo->TotalUsage();
 
-    if (IsTreatedAsTemporary(aPersistenceType, aOrigin)) {
+    if (temporaryStorage) {
       // Temporary storage has no limit for origin usage (there's a group and
       // the global limit though).
       quotaMaxBytes = 0;
     }
     else {
       quotaMaxBytes = GetStorageQuotaMB() * 1024 * 1024;
       if (totalUsageBytes > quotaMaxBytes) {
         NS_WARNING("Origin is already using more storage than allowed!");
@@ -2090,160 +1821,153 @@ QuotaManager::MaybeUpgradeIndexedDBDirec
 
   return NS_OK;
 }
 
 nsresult
 QuotaManager::EnsureOriginIsInitialized(PersistenceType aPersistenceType,
                                         const nsACString& aGroup,
                                         const nsACString& aOrigin,
-                                        bool aHasUnlimStoragePerm,
+                                        bool aTrackQuota,
                                         nsIFile** aDirectory)
 {
   AssertIsOnIOThread();
 
   nsresult rv = MaybeUpgradeIndexedDBDirectory();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Get directory for this origin and persistence type.
   nsCOMPtr<nsIFile> directory;
   rv = GetDirectoryForOrigin(aPersistenceType, aOrigin,
                              getter_AddRefs(directory));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (IsTreatedAsPersistent(aPersistenceType, aOrigin)) {
+  if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
     if (mInitializedOrigins.Contains(aOrigin)) {
       NS_ADDREF(*aDirectory = directory);
       return NS_OK;
     }
-  } else if (!mTemporaryStorageInitialized) {
-    rv = InitializeRepository(aPersistenceType);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      // We have to cleanup partially initialized quota for temporary storage.
-      RemoveQuotaForTemporaryStorage();
-
-      return rv;
+
+    bool created;
+    rv = EnsureDirectory(directory, &created);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (created) {
+      rv = CreateDirectoryUpgradeStamp(directory);
+      NS_ENSURE_SUCCESS(rv, rv);
     }
 
-    rv = InitializeRepository(ComplementaryPersistenceType(aPersistenceType));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      // We have to cleanup partially initialized quota for temporary storage.
-      RemoveQuotaForTemporaryStorage();
-
-      return rv;
+    rv = InitializeOrigin(aPersistenceType, aGroup, aOrigin, aTrackQuota, 0,
+                          directory);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    mInitializedOrigins.AppendElement(aOrigin);
+
+    directory.forget(aDirectory);
+    return NS_OK;
+  }
+
+  NS_ASSERTION(aPersistenceType == PERSISTENCE_TYPE_TEMPORARY, "Huh?");
+  NS_ASSERTION(aTrackQuota, "Huh?");
+
+  if (!mTemporaryStorageInitialized) {
+    nsCOMPtr<nsIFile> parentDirectory;
+    rv = directory->GetParent(getter_AddRefs(parentDirectory));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    bool created;
+    rv = EnsureDirectory(parentDirectory, &created);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsISimpleEnumerator> entries;
+    rv = parentDirectory->GetDirectoryEntries(getter_AddRefs(entries));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    bool hasMore;
+    while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
+      nsCOMPtr<nsISupports> entry;
+      rv = entries->GetNext(getter_AddRefs(entry));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      nsCOMPtr<nsIFile> childDirectory = do_QueryInterface(entry);
+      NS_ENSURE_TRUE(childDirectory, NS_NOINTERFACE);
+
+      bool isDirectory;
+      rv = childDirectory->IsDirectory(&isDirectory);
+      NS_ENSURE_SUCCESS(rv, rv);
+      NS_ENSURE_TRUE(isDirectory, NS_ERROR_UNEXPECTED);
+
+      int64_t timestamp;
+      nsCString group;
+      nsCString origin;
+      rv = GetDirectoryMetadata(childDirectory, &timestamp, group, origin);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      rv = InitializeOrigin(aPersistenceType, group, origin, aTrackQuota,
+                            timestamp, childDirectory);
+      if (NS_FAILED(rv)) {
+        NS_WARNING("Failed to initialize origin!");
+
+        // We have to cleanup partially initialized quota for temporary storage.
+        RemoveQuotaForPersistenceType(aPersistenceType);
+
+        return rv;
+      }
     }
 
     if (gFixedLimitKB >= 0) {
       mTemporaryStorageLimit = gFixedLimitKB * 1024;
     }
     else {
-      nsCOMPtr<nsIFile> storageDir =
-        do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
-      }
-
-      rv = storageDir->InitWithPath(GetStoragePath());
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
-      }
-
-      rv = GetTemporaryStorageLimit(storageDir, mTemporaryStorageUsage,
+      rv = GetTemporaryStorageLimit(parentDirectory, mTemporaryStorageUsage,
                                     &mTemporaryStorageLimit);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     mTemporaryStorageInitialized = true;
 
     CheckTemporaryStorageLimits();
   }
 
-  nsCOMPtr<nsIFile> parentDirectory;
-  rv = directory->GetParent(getter_AddRefs(parentDirectory));
-  NS_ENSURE_SUCCESS(rv, rv);
-
   bool created;
-  rv = EnsureDirectory(parentDirectory, &created);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  int64_t timestamp;
-
   rv = EnsureDirectory(directory, &created);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (IsTreatedAsPersistent(aPersistenceType, aOrigin)) {
-    if (created) {
-      timestamp = PR_Now();
-
-      if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
-        rv = CreateDirectoryMetadataLastModifiedTime(directory, timestamp);
-      } else {
-        rv = CreateDirectoryMetadata(directory, timestamp, aGroup, aOrigin);
-      }
-      NS_ENSURE_SUCCESS(rv, rv);
-    } else {
-      if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
-        rv = GetDirectoryMetadataLastModifiedTime(directory, &timestamp);
-        NS_ENSURE_SUCCESS(rv, rv);
-      } else {
-        nsCOMPtr<nsIBinaryInputStream> stream;
-        rv = GetDirectoryMetadataInputStream(directory, true,
-                                             getter_AddRefs(stream));
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        uint64_t ts;
-        rv = stream->Read64(&ts);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        timestamp = ts;
-      }
-    }
-
-    rv = InitializeOrigin(aPersistenceType, aGroup, aOrigin,
-                          aHasUnlimStoragePerm, timestamp, directory);
+  if (created) {
+    int64_t timestamp = PR_Now();
+
+    rv = CreateDirectoryMetadata(directory, timestamp, aGroup, aOrigin);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    mInitializedOrigins.AppendElement(aOrigin);
-  } else if (created) {
-    timestamp = PR_Now();
-
-    if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
-      rv = CreateDirectoryMetadataLastModifiedTime(directory, timestamp);
-    } else {
-      rv = CreateDirectoryMetadata(directory, timestamp, aGroup, aOrigin);
-    }
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = InitializeOrigin(aPersistenceType, aGroup, aOrigin,
-                          aHasUnlimStoragePerm, timestamp, directory);
+    rv = InitializeOrigin(aPersistenceType, aGroup, aOrigin, aTrackQuota,
+                          timestamp, directory);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   directory.forget(aDirectory);
   return NS_OK;
 }
 
 void
 QuotaManager::OriginClearCompleted(
                                   PersistenceType aPersistenceType,
                                   const OriginOrPatternString& aOriginOrPattern)
 {
   AssertIsOnIOThread();
 
-  if (aOriginOrPattern.IsOrigin()) {
-    if (IsTreatedAsPersistent(aPersistenceType, aOriginOrPattern)) {
+  if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
+    if (aOriginOrPattern.IsOrigin()) {
       mInitializedOrigins.RemoveElement(aOriginOrPattern);
     }
-  }
-  else {
-    for (uint32_t index = mInitializedOrigins.Length(); index > 0; index--) {
-      nsCString& initializedOrigin = mInitializedOrigins[index - 1];
-      if (PatternMatchesOrigin(aOriginOrPattern, initializedOrigin) &&
-          IsTreatedAsPersistent(aPersistenceType, aOriginOrPattern)) {
-        mInitializedOrigins.RemoveElementAt(index - 1);
+    else {
+      for (uint32_t index = mInitializedOrigins.Length(); index > 0; index--) {
+        if (PatternMatchesOrigin(aOriginOrPattern,
+                                 mInitializedOrigins[index - 1])) {
+          mInitializedOrigins.RemoveElementAt(index - 1);
+        }
       }
     }
   }
 
   for (uint32_t index = 0; index < Client::TYPE_MAX; index++) {
     mClients[index]->OnOriginClearCompleted(aPersistenceType, aOriginOrPattern);
   }
 }
@@ -2310,46 +2034,45 @@ QuotaManager::GetStorageId(PersistenceTy
   aDatabaseId = str;
 }
 
 // static
 nsresult
 QuotaManager::GetInfoFromURI(nsIURI* aURI,
                              uint32_t aAppId,
                              bool aInMozBrowser,
-                             PersistenceType aPersistenceType,
                              nsACString* aGroup,
                              nsACString* aOrigin,
-                             bool* aIsApp,
-                             bool* aHasUnlimStoragePerm)
+                             StoragePrivilege* aPrivilege,
+                             PersistenceType* aDefaultPersistenceType)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aURI);
 
   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
   NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIPrincipal> principal;
   nsresult rv = secMan->GetAppCodebasePrincipal(aURI, aAppId, aInMozBrowser,
                                                 getter_AddRefs(principal));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = GetInfoFromPrincipal(principal, aPersistenceType, aGroup, aOrigin,
-                            aIsApp, aHasUnlimStoragePerm);
+  rv = GetInfoFromPrincipal(principal, aGroup, aOrigin, aPrivilege,
+                            aDefaultPersistenceType);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 static nsresult
 TryGetInfoForAboutURI(nsIPrincipal* aPrincipal,
                       nsACString& aGroup,
                       nsACString& aASCIIOrigin,
-                      bool* aIsApp,
-                      bool* aHasUnlimStoragePerm)
+                      StoragePrivilege* aPrivilege,
+                      PersistenceType* aDefaultPersistenceType)
 {
   NS_ASSERTION(aPrincipal, "Don't hand me a null principal!");
 
   nsCOMPtr<nsIURI> uri;
   nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
   NS_ENSURE_SUCCESS(rv, rv);
   if (!uri) {
     return NS_ERROR_NOT_AVAILABLE;
@@ -2385,58 +2108,48 @@ TryGetInfoForAboutURI(nsIPrincipal* aPri
 
     origin = scheme + NS_LITERAL_CSTRING(":") + NS_ConvertUTF16toUTF8(postfix);
   }
 
   ToLowerCase(origin);
   aGroup.Assign(origin);
   aASCIIOrigin.Assign(origin);
 
-  if (aIsApp) {
-    *aIsApp = false;
-  }
-
-  if (aHasUnlimStoragePerm) {
-    *aHasUnlimStoragePerm = false;
+  if (aPrivilege) {
+    *aPrivilege = Content;
   }
 
-  // XXX This is temporary, we don't have regular .metadata files for persistent
-  //     storage yet, so we have to use sanitized origin strings and create
-  //     separate group for each origin.
-  nsCString originSanitized(aASCIIOrigin);
-  SanitizeOriginString(originSanitized);
-  aASCIIOrigin = originSanitized;
-
-  // XXX The group is already the same as the origin.
+  if (aDefaultPersistenceType) {
+    *aDefaultPersistenceType = PERSISTENCE_TYPE_PERSISTENT;
+  }
 
   return NS_OK;
 }
 
 // static
 nsresult
 QuotaManager::GetInfoFromPrincipal(nsIPrincipal* aPrincipal,
-                                   PersistenceType aPersistenceType,
                                    nsACString* aGroup,
                                    nsACString* aOrigin,
-                                   bool* aIsApp,
-                                   bool* aHasUnlimStoragePerm)
+                                   StoragePrivilege* aPrivilege,
+                                   PersistenceType* aDefaultPersistenceType)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aPrincipal);
 
   if (aGroup && aOrigin) {
     nsresult rv = TryGetInfoForAboutURI(aPrincipal, *aGroup, *aOrigin,
-                                        aIsApp, aHasUnlimStoragePerm);
+                                        aPrivilege, aDefaultPersistenceType);
     if (NS_SUCCEEDED(rv)) {
       return NS_OK;
     }
   }
 
   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
-    GetInfoForChrome(aGroup, aOrigin, aIsApp, aHasUnlimStoragePerm);
+    GetInfoForChrome(aGroup, aOrigin, aPrivilege, aDefaultPersistenceType);
     return NS_OK;
   }
 
   bool isNullPrincipal;
   nsresult rv = aPrincipal->GetIsNullPrincipal(&isNullPrincipal);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (isNullPrincipal) {
@@ -2486,125 +2199,73 @@ QuotaManager::GetInfoFromPrincipal(nsIPr
       aGroup->Assign(jarPrefix + baseDomain);
     }
   }
 
   if (aOrigin) {
     aOrigin->Assign(jarPrefix + origin);
   }
 
-  if (aIsApp) {
-    *aIsApp = aPrincipal->GetAppStatus() !=
-                nsIPrincipal::APP_STATUS_NOT_INSTALLED;
-  }
-
-  if (aHasUnlimStoragePerm) {
-    *aHasUnlimStoragePerm = CheckQuotaHelper::GetQuotaPermission(aPrincipal) ==
-                              nsIPermissionManager::ALLOW_ACTION;
+  if (aPrivilege) {
+    *aPrivilege = Content;
   }
 
-  // XXX This is temporary, we don't have regular .metadata files for persistent
-  //     storage yet, so we have to use sanitized origin strings and create
-  //     separate group for each origin.
-  if (aOrigin) {
-    nsCString originSanitized(*aOrigin);
-    SanitizeOriginString(originSanitized);
-    *aOrigin = originSanitized;
-  }
-  if (aGroup && aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
-    *aGroup = *aOrigin;
+  if (aDefaultPersistenceType) {
+    *aDefaultPersistenceType = PERSISTENCE_TYPE_PERSISTENT;
   }
 
   return NS_OK;
 }
 
 // static
 nsresult
 QuotaManager::GetInfoFromWindow(nsPIDOMWindow* aWindow,
-                                PersistenceType aPersistenceType,
                                 nsACString* aGroup,
                                 nsACString* aOrigin,
-                                bool* aIsApp,
-                                bool* aHasUnlimStoragePerm)
+                                StoragePrivilege* aPrivilege,
+                                PersistenceType* aDefaultPersistenceType)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aWindow);
 
   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
   NS_ENSURE_TRUE(sop, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
   NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
 
-  nsresult rv = GetInfoFromPrincipal(principal, aPersistenceType, aGroup,
-                                     aOrigin, aIsApp, aHasUnlimStoragePerm);
+  nsresult rv = GetInfoFromPrincipal(principal, aGroup, aOrigin, aPrivilege,
+                                     aDefaultPersistenceType);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 // static
 void
 QuotaManager::GetInfoForChrome(nsACString* aGroup,
                                nsACString* aOrigin,
-                               bool* aIsApp,
-                               bool* aHasUnlimStoragePerm)
+                               StoragePrivilege* aPrivilege,
+                               PersistenceType* aDefaultPersistenceType)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(nsContentUtils::IsCallerChrome());
 
   if (aGroup) {
     ChromeOrigin(*aGroup);
   }
   if (aOrigin) {
     ChromeOrigin(*aOrigin);
   }
-  if (aIsApp) {
-    *aIsApp = false;
-  }
-  if (aHasUnlimStoragePerm) {
-    *aHasUnlimStoragePerm = false;
-  }
-
-  // XXX The chrome origin doesn't have to be sanitized and the group is already
-  //     the same as the origin.
-}
-
-bool
-QuotaManager::IsTreatedAsPersistent(PersistenceType aPersistenceType,
-                                    const nsACString& aOrigin)
-{
-  if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT &&
-      (aOrigin.Equals("chrome") ||
-       aOrigin.Equals("moz-safe-about+home"))) {
-    return true;
+  if (aPrivilege) {
+    *aPrivilege = Chrome;
   }
-
-  return false;
-}
-
-// static
-bool
-QuotaManager::IsQuotaEnforced(PersistenceType aPersistenceType,
-                              const nsACString& aOrigin,
-                              bool aHasUnlimStoragePerm)
-{
-  bool result;
-
-  if (IsTreatedAsTemporary(aPersistenceType, aOrigin)) {
-    result = true;
-  } else {
-    if (aOrigin.Equals("chrome")) {
-      result = false;
-    } else {
-      result = !aHasUnlimStoragePerm;
-    }
+  if (aDefaultPersistenceType) {
+    *aDefaultPersistenceType = PERSISTENCE_TYPE_PERSISTENT;
   }
-
-  return result;
 }
 
 // static
 void
 QuotaManager::ChromeOrigin(nsACString& aOrigin)
 {
   aOrigin.AssignLiteral(kChromeOrigin);
 }
@@ -2627,34 +2288,27 @@ QuotaManager::GetUsageForURI(nsIURI* aUR
   // This only works from the main process.
   NS_ENSURE_TRUE(IsMainProcess(), NS_ERROR_NOT_AVAILABLE);
 
   if (!aOptionalArgCount) {
     aAppId = nsIScriptSecurityManager::NO_APP_ID;
   }
 
   // Figure out which origin we're dealing with.
-  nsCString persistentGroup;
+  nsCString group;
   nsCString origin;
-  nsresult rv = GetInfoFromURI(aURI, aAppId, aInMozBrowserOnly,
-                               PERSISTENCE_TYPE_PERSISTENT, &persistentGroup,
-                               &origin, nullptr, nullptr);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCString temporaryGroup;
-  rv = GetInfoFromURI(aURI, aAppId, aInMozBrowserOnly,
-                      PERSISTENCE_TYPE_TEMPORARY, &temporaryGroup,
-                      nullptr, nullptr, nullptr);
+  nsresult rv = GetInfoFromURI(aURI, aAppId, aInMozBrowserOnly, &group, &origin,
+                               nullptr, nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
   OriginOrPatternString oops = OriginOrPatternString::FromOrigin(origin);
 
   nsRefPtr<AsyncUsageRunnable> runnable =
-    new AsyncUsageRunnable(aAppId, aInMozBrowserOnly, persistentGroup,
-                           temporaryGroup, oops, aURI, aCallback);
+    new AsyncUsageRunnable(aAppId, aInMozBrowserOnly, group, oops, aURI,
+                           aCallback);
 
   // Put the computation runnable in the queue.
   rv = WaitForOpenAllowed(oops, Nullable<PersistenceType>(), EmptyCString(),
                           runnable);
   NS_ENSURE_SUCCESS(rv, rv);
 
   runnable->AdvanceState();
 
@@ -2722,23 +2376,20 @@ QuotaManager::ClearStoragesForURI(nsIURI
   NS_ENSURE_TRUE(IsMainProcess(), NS_ERROR_NOT_AVAILABLE);
 
   if (!aOptionalArgCount) {
     aAppId = nsIScriptSecurityManager::NO_APP_ID;
   }
 
   // Figure out which origin we're dealing with.
   nsCString origin;
-  rv = GetInfoFromURI(aURI, aAppId, aInMozBrowserOnly, PERSISTENCE_TYPE_INVALID,
-                      nullptr, &origin, nullptr, nullptr);
+  rv = GetInfoFromURI(aURI, aAppId, aInMozBrowserOnly, nullptr, &origin,
+                      nullptr, nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // XXX We don't care about the group, no need to update it for persistence
-  //     storage.
-
   nsAutoCString pattern;
   GetOriginPatternString(aAppId, aInMozBrowserOnly, origin, pattern);
 
   // If there is a pending or running clear operation for this origin, return
   // immediately.
   if (IsClearOriginPending(pattern, persistenceType)) {
     return NS_OK;
   }
@@ -3325,54 +2976,37 @@ QuotaManager::ClearStoragesForApp(uint32
 PLDHashOperator
 QuotaManager::GetOriginsExceedingGroupLimit(const nsACString& aKey,
                                             GroupInfoPair* aValue,
                                             void* aUserArg)
 {
   NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
   NS_ASSERTION(aValue, "Null pointer!");
 
-  uint64_t groupUsage = 0;
-
-  nsRefPtr<GroupInfo> persistentGroupInfo =
-    aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_PERSISTENT);
-  if (persistentGroupInfo) {
-    groupUsage += persistentGroupInfo->LockedGetTemporaryUsage();
-  }
-
-  nsRefPtr<GroupInfo> temporaryGroupInfo =
+  nsRefPtr<GroupInfo> groupInfo =
     aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
-  if (temporaryGroupInfo) {
-    groupUsage += temporaryGroupInfo->LockedGetTemporaryUsage();
-  }
-
-  if (groupUsage > 0) {
+  if (groupInfo) {
     QuotaManager* quotaManager = QuotaManager::Get();
     NS_ASSERTION(quotaManager, "Shouldn't be null!");
 
-    if (groupUsage > quotaManager->GetGroupLimit()) {
+    if (groupInfo->mUsage > quotaManager->GetGroupLimit()) {
       nsTArray<OriginInfo*>* doomedOriginInfos =
         static_cast<nsTArray<OriginInfo*>*>(aUserArg);
 
-      nsTArray<OriginInfo*> originInfos;
-      if (persistentGroupInfo) {
-        persistentGroupInfo->LockedGetTemporaryOriginInfos(&originInfos);
-      }
-      if (temporaryGroupInfo) {
-        temporaryGroupInfo->LockedGetTemporaryOriginInfos(&originInfos);
-      }
+      nsTArray<nsRefPtr<OriginInfo> >& originInfos = groupInfo->mOriginInfos;
       originInfos.Sort(OriginInfoLRUComparator());
 
+      uint64_t usage = groupInfo->mUsage;
       for (uint32_t i = 0; i < originInfos.Length(); i++) {
         OriginInfo* originInfo = originInfos[i];
 
         doomedOriginInfos->AppendElement(originInfo);
-        groupUsage -= originInfo->mUsage;
-
-        if (groupUsage <= quotaManager->GetGroupLimit()) {
+        usage -= originInfo->mUsage;
+
+        if (usage <= quotaManager->GetGroupLimit()) {
           break;
         }
       }
     }
   }
 
   return PL_DHASH_NEXT;
 }
@@ -3381,28 +3015,23 @@ QuotaManager::GetOriginsExceedingGroupLi
 PLDHashOperator
 QuotaManager::GetAllTemporaryStorageOrigins(const nsACString& aKey,
                                             GroupInfoPair* aValue,
                                             void* aUserArg)
 {
   NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
   NS_ASSERTION(aValue, "Null pointer!");
 
-  nsTArray<OriginInfo*>* originInfos =
-    static_cast<nsTArray<OriginInfo*>*>(aUserArg);
-
   nsRefPtr<GroupInfo> groupInfo =
-    aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_PERSISTENT);
+    aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
   if (groupInfo) {
-    groupInfo->LockedGetTemporaryOriginInfos(originInfos);
-  }
-
-  groupInfo = aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
-  if (groupInfo) {
-    groupInfo->LockedGetTemporaryOriginInfos(originInfos);
+    nsTArray<OriginInfo*>* originInfos =
+      static_cast<nsTArray<OriginInfo*>*>(aUserArg);
+
+    originInfos->AppendElements(groupInfo->mOriginInfos);
   }
 
   return PL_DHASH_NEXT;
 }
 
 void
 QuotaManager::CheckTemporaryStorageLimits()
 {
@@ -3443,116 +3072,98 @@ QuotaManager::CheckTemporaryStorageLimit
         usage += originInfos[i]->mUsage;
       }
 
       doomedOriginInfos.AppendElements(originInfos);
     }
   }
 
   for (uint32_t index = 0; index < doomedOriginInfos.Length(); index++) {
-    OriginInfo* doomedOriginInfo = doomedOriginInfos[index];
-
-    DeleteFilesForOrigin(doomedOriginInfo->mGroupInfo->mPersistenceType,
-                         doomedOriginInfo->mOrigin);
+    DeleteTemporaryFilesForOrigin(doomedOriginInfos[index]->mOrigin);
   }
 
-  nsTArray<OriginParams> doomedOrigins;
+  nsTArray<nsCString> doomedOrigins;
   {
     MutexAutoLock lock(mQuotaMutex);
 
     for (uint32_t index = 0; index < doomedOriginInfos.Length(); index++) {
       OriginInfo* doomedOriginInfo = doomedOriginInfos[index];
 
-      PersistenceType persistenceType =
-        doomedOriginInfo->mGroupInfo->mPersistenceType;
       nsCString group = doomedOriginInfo->mGroupInfo->mGroup;
       nsCString origin = doomedOriginInfo->mOrigin;
-      LockedRemoveQuotaForOrigin(persistenceType, group, origin);
+      LockedRemoveQuotaForOrigin(PERSISTENCE_TYPE_TEMPORARY, group, origin);
 
 #ifdef DEBUG
       doomedOriginInfos[index] = nullptr;
 #endif
 
-      doomedOrigins.AppendElement(OriginParams(persistenceType, origin));
+      doomedOrigins.AppendElement(origin);
     }
   }
 
   for (uint32_t index = 0; index < doomedOrigins.Length(); index++) {
-    const OriginParams& doomedOrigin = doomedOrigins[index];
-
     OriginClearCompleted(
-                       doomedOrigin.mPersistenceType,
-                       OriginOrPatternString::FromOrigin(doomedOrigin.mOrigin));
+                       PERSISTENCE_TYPE_TEMPORARY,
+                       OriginOrPatternString::FromOrigin(doomedOrigins[index]));
   }
 }
 
 // static
 PLDHashOperator
-QuotaManager::AddLiveStorageOrigins(const nsACString& aKey,
-                                    nsTArray<nsIOfflineStorage*>* aValue,
-                                    void* aUserArg)
+QuotaManager::AddTemporaryStorageOrigins(
+                                       const nsACString& aKey,
+                                       ArrayCluster<nsIOfflineStorage*>* aValue,
+                                       void* aUserArg)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
   NS_ASSERTION(aValue, "Null pointer!");
   NS_ASSERTION(aUserArg, "Null pointer!");
 
   OriginCollection& collection = *static_cast<OriginCollection*>(aUserArg);
 
-  if (!collection.ContainsOrigin(aKey)) {
-    collection.AddOrigin(aKey);
+  if (collection.ContainsOrigin(aKey)) {
+    return PL_DHASH_NEXT;
+  }
+
+  for (uint32_t i = 0; i < Client::TYPE_MAX; i++) {
+    nsTArray<nsIOfflineStorage*>& array = (*aValue)[i];
+    for (uint32_t j = 0; j < array.Length(); j++) {
+      nsIOfflineStorage*& storage = array[j];
+      if (storage->Type() == PERSISTENCE_TYPE_TEMPORARY) {
+        collection.AddOrigin(aKey);
+        return PL_DHASH_NEXT;
+      }
+    }
   }
 
   return PL_DHASH_NEXT;
 }
 
 // static
 PLDHashOperator
 QuotaManager::GetInactiveTemporaryStorageOrigins(const nsACString& aKey,
                                                  GroupInfoPair* aValue,
                                                  void* aUserArg)
 {
   NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
   NS_ASSERTION(aValue, "Null pointer!");
   NS_ASSERTION(aUserArg, "Null pointer!");
 
-  InactiveOriginsInfo* info = static_cast<InactiveOriginsInfo*>(aUserArg);
-
   nsRefPtr<GroupInfo> groupInfo =
-    aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_PERSISTENT);
+    aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
   if (groupInfo) {
+    InactiveOriginsInfo* info = static_cast<InactiveOriginsInfo*>(aUserArg);
+
     nsTArray<nsRefPtr<OriginInfo> >& originInfos = groupInfo->mOriginInfos;
 
     for (uint32_t i = 0; i < originInfos.Length(); i++) {
       OriginInfo* originInfo = originInfos[i];
 
-      if (originInfo->IsTreatedAsPersistent()) {
-        continue;
-      }
-
-      if (!info->persistentCollection.ContainsOrigin(originInfo->mOrigin)) {
-        NS_ASSERTION(!originInfo->mQuotaObjects.Count(),
-                     "Inactive origin shouldn't have open files!");
-        info->origins.AppendElement(originInfo);
-      }
-    }
-  }
-
-  groupInfo = aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
-  if (groupInfo) {
-    nsTArray<nsRefPtr<OriginInfo> >& originInfos = groupInfo->mOriginInfos;
-
-    for (uint32_t i = 0; i < originInfos.Length(); i++) {
-      OriginInfo* originInfo = originInfos[i];
-
-      if (originInfo->IsTreatedAsPersistent()) {
-        continue;
-      }
-
-      if (!info->temporaryCollection.ContainsOrigin(originInfo->mOrigin)) {
+      if (!info->collection.ContainsOrigin(originInfo->mOrigin)) {
         NS_ASSERTION(!originInfo->mQuotaObjects.Count(),
                      "Inactive origin shouldn't have open files!");
         info->origins.AppendElement(originInfo);
       }
     }
   }
 
   return PL_DHASH_NEXT;
@@ -3560,80 +3171,50 @@ QuotaManager::GetInactiveTemporaryStorag
 
 uint64_t
 QuotaManager::CollectOriginsForEviction(uint64_t aMinSizeToBeFreed,
                                         nsTArray<OriginInfo*>& aOriginInfos)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   // Collect active origins first.
-  OriginCollection persistentOriginCollection;
-  OriginCollection temporaryOriginCollection;
+  OriginCollection originCollection;
 
   // Add patterns and origins that have running or pending synchronized ops.
   // (add patterns first to reduce redundancy in the origin collection).
   uint32_t index;
   for (index = 0; index < mSynchronizedOps.Length(); index++) {
     nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
-
-    const OriginOrPatternString& originOrPattern = op->mOriginOrPattern;
-
-    if (!originOrPattern.IsPattern()) {
-      continue;
-    }
-
-    Nullable<PersistenceType>& persistenceType = op->mPersistenceType;
-
-    if (persistenceType.IsNull()) {
-      persistentOriginCollection.AddPattern(originOrPattern);
-      temporaryOriginCollection.AddPattern(originOrPattern);
-    } else if (persistenceType.Value() == PERSISTENCE_TYPE_PERSISTENT) {
-      persistentOriginCollection.AddPattern(originOrPattern);
-    } else {
-      MOZ_ASSERT(persistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY);
-      temporaryOriginCollection.AddPattern(originOrPattern);
+    if (op->mPersistenceType.IsNull() ||
+        op->mPersistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY) {
+      if (op->mOriginOrPattern.IsPattern() &&
+          !originCollection.ContainsPattern(op->mOriginOrPattern)) {
+        originCollection.AddPattern(op->mOriginOrPattern);
+      }
     }
   }
 
   for (index = 0; index < mSynchronizedOps.Length(); index++) {
     nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
-
-    const OriginOrPatternString& originOrPattern = op->mOriginOrPattern;
-
-    if (!originOrPattern.IsOrigin()) {
-      continue;
-    }
-
-    Nullable<PersistenceType>& persistenceType = op->mPersistenceType;
-
-    if (persistenceType.IsNull()) {
-      persistentOriginCollection.AddOrigin(originOrPattern);
-      temporaryOriginCollection.AddOrigin(originOrPattern);
-    } else if (persistenceType.Value() == PERSISTENCE_TYPE_PERSISTENT) {
-      persistentOriginCollection.AddOrigin(originOrPattern);
-    } else {
-      MOZ_ASSERT(persistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY);
-      temporaryOriginCollection.AddOrigin(originOrPattern);
+    if (op->mPersistenceType.IsNull() ||
+        op->mPersistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY) {
+      if (op->mOriginOrPattern.IsOrigin() &&
+          !originCollection.ContainsOrigin(op->mOriginOrPattern)) {
+        originCollection.AddOrigin(op->mOriginOrPattern);
+      }
     }
   }
 
-  // Add origins that have live persistent storages.
-  mPersistentLiveStorageTable.EnumerateRead(AddLiveStorageOrigins,
-                                            &persistentOriginCollection);
-
   // Add origins that have live temporary storages.
-  mTemporaryLiveStorageTable.EnumerateRead(AddLiveStorageOrigins,
-                                           &temporaryOriginCollection);
+  mLiveStorages.EnumerateRead(AddTemporaryStorageOrigins, &originCollection);
 
   // Enumerate inactive origins. This must be protected by the mutex.
   nsTArray<OriginInfo*> inactiveOrigins;
   {
-    InactiveOriginsInfo info(persistentOriginCollection,
-                             temporaryOriginCollection,
-                             inactiveOrigins);
+    InactiveOriginsInfo info(originCollection, inactiveOrigins);
     MutexAutoLock lock(mQuotaMutex);
     mGroupInfoPairs.EnumerateRead(GetInactiveTemporaryStorageOrigins, &info);
   }
 
   // We now have a list of all inactive origins. So it's safe to sort the list
   // and calculate available size without holding the lock.
 
   // Sort by the origin access time.
@@ -3651,78 +3232,72 @@ QuotaManager::CollectOriginsForEviction(
     sizeToBeFreed += inactiveOrigins[index]->mUsage;
   }
 
   if (sizeToBeFreed >= aMinSizeToBeFreed) {
     // Success, add synchronized ops for these origins, so any other
     // operations for them will be delayed (until origin eviction is finalized).
 
     for(index = 0; index < inactiveOrigins.Length(); index++) {
-      OriginInfo* inactiveOrigin = inactiveOrigins[index];
-
       OriginOrPatternString oops =
-        OriginOrPatternString::FromOrigin(inactiveOrigin->mOrigin);
-
-      Nullable<PersistenceType> persistenceType =
-        Nullable<PersistenceType>(inactiveOrigin->mGroupInfo->mPersistenceType);
-
-      AddSynchronizedOp(oops, persistenceType);
+        OriginOrPatternString::FromOrigin(inactiveOrigins[index]->mOrigin);
+
+      AddSynchronizedOp(oops,
+                        Nullable<PersistenceType>(PERSISTENCE_TYPE_TEMPORARY));
     }
 
     inactiveOrigins.SwapElements(aOriginInfos);
     return sizeToBeFreed;
   }
 
   return 0;
 }
 
 void
-QuotaManager::DeleteFilesForOrigin(PersistenceType aPersistenceType,
-                                   const nsACString& aOrigin)
+QuotaManager::DeleteTemporaryFilesForOrigin(const nsACString& aOrigin)
 {
   nsCOMPtr<nsIFile> directory;
-  nsresult rv = GetDirectoryForOrigin(aPersistenceType, aOrigin,
+  nsresult rv = GetDirectoryForOrigin(PERSISTENCE_TYPE_TEMPORARY, aOrigin,
                                       getter_AddRefs(directory));
   NS_ENSURE_SUCCESS_VOID(rv);
 
   rv = directory->Remove(true);
   if (rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST &&
       rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
     // This should never fail if we've closed all storage connections
     // correctly...
     NS_ERROR("Failed to remove directory!");
   }
 }
 
 void
-QuotaManager::FinalizeOriginEviction(nsTArray<OriginParams>& aOrigins)
+QuotaManager::FinalizeOriginEviction(nsTArray<nsCString>& aOrigins)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
   nsRefPtr<FinalizeOriginEvictionRunnable> runnable =
     new FinalizeOriginEvictionRunnable(aOrigins);
 
   nsresult rv = IsOnIOThread() ? runnable->RunImmediately()
                                : runnable->Dispatch();
   NS_ENSURE_SUCCESS_VOID(rv);
 }
 
 void
-QuotaManager::SaveOriginAccessTime(PersistenceType aPersistenceType,
-                                   const nsACString& aOrigin,
+QuotaManager::SaveOriginAccessTime(const nsACString& aOrigin,
                                    int64_t aTimestamp)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (QuotaManager::IsShuttingDown()) {
     return;
   }
 
   nsRefPtr<SaveOriginAccessTimeRunnable> runnable =
-    new SaveOriginAccessTimeRunnable(aPersistenceType, aOrigin, aTimestamp);
+    new SaveOriginAccessTimeRunnable(aOrigin, aTimestamp);
 
   if (NS_FAILED(mIOThread->Dispatch(runnable, NS_DISPATCH_NORMAL))) {
     NS_WARNING("Failed to dispatch runnable!");
   }
 }
 
 void
 QuotaManager::GetOriginPatternString(uint32_t aAppId,
@@ -3762,32 +3337,16 @@ QuotaManager::GetOriginPatternString(uin
     NS_ASSERTION(PatternMatchesOrigin(pattern, aOrigin),
                  "Origin doesn't match parameters!");
   }
 #endif
 
   _retval = aOrigin;
 }
 
-auto
-QuotaManager::GetLiveStorageTable(PersistenceType aPersistenceType)
-  -> LiveStorageTable&
-{
-  switch (aPersistenceType) {
-    case PERSISTENCE_TYPE_PERSISTENT:
-      return mPersistentLiveStorageTable;
-    case PERSISTENCE_TYPE_TEMPORARY:
-      return mTemporaryLiveStorageTable;
-
-    case PERSISTENCE_TYPE_INVALID:
-    default:
-      MOZ_CRASH("Bad persistence type value!");
-  }
-}
-
 SynchronizedOp::SynchronizedOp(const OriginOrPatternString& aOriginOrPattern,
                                Nullable<PersistenceType> aPersistenceType,
                                const nsACString& aId)
 : mOriginOrPattern(aOriginOrPattern), mPersistenceType(aPersistenceType),
   mId(aId)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   MOZ_COUNT_CTOR(SynchronizedOp);
@@ -3988,31 +3547,29 @@ OriginClearRunnable::DeleteFiles(QuotaMa
   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
     nsCOMPtr<nsISupports> entry;
     rv = entries->GetNext(getter_AddRefs(entry));
     NS_ENSURE_SUCCESS_VOID(rv);
 
     nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
     NS_ASSERTION(file, "Don't know what this is!");
 
-    nsString leafName;
-    rv = file->GetLeafName(leafName);
-    NS_ENSURE_SUCCESS_VOID(rv);
-
     bool isDirectory;
     rv = file->IsDirectory(&isDirectory);
     NS_ENSURE_SUCCESS_VOID(rv);
 
     if (!isDirectory) {
-      if (!leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
-        NS_WARNING("Something in the IndexedDB directory that doesn't belong!");
-      }
+      NS_WARNING("Something in the IndexedDB directory that doesn't belong!");
       continue;
     }
 
+    nsString leafName;
+    rv = file->GetLeafName(leafName);
+    NS_ENSURE_SUCCESS_VOID(rv);
+
     // Skip storages for other apps.
     if (!PatternMatchesOrigin(originSanitized,
                               NS_ConvertUTF16toUTF8(leafName))) {
       continue;
     }
 
     for (uint32_t index = 0; index < 10; index++) {
       // We can't guarantee that this will always succeed on Windows...
@@ -4105,34 +3662,31 @@ OriginClearRunnable::Run()
   }
 
   NS_NOTREACHED("Should never get here!");
   return NS_ERROR_UNEXPECTED;
 }
 
 AsyncUsageRunnable::AsyncUsageRunnable(uint32_t aAppId,
                                        bool aInMozBrowserOnly,
-                                       const nsACString& aPersistentGroup,
-                                       const nsACString& aTemporaryGroup,
+                                       const nsACString& aGroup,
                                        const OriginOrPatternString& aOrigin,
                                        nsIURI* aURI,
                                        nsIUsageCallback* aCallback)
 : mURI(aURI),
   mCallback(aCallback),
   mAppId(aAppId),
-  mPersistentGroup(aPersistentGroup),
-  mTemporaryGroup(aTemporaryGroup),
+  mGroup(aGroup),
   mOrigin(aOrigin),
   mCallbackState(Pending),
   mInMozBrowserOnly(aInMozBrowserOnly)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aURI, "Null pointer!");
-  NS_ASSERTION(!aPersistentGroup.IsEmpty(), "Empty group!");
-  NS_ASSERTION(!aTemporaryGroup.IsEmpty(), "Empty group!");
+  NS_ASSERTION(!aGroup.IsEmpty(), "Empty group!");
   NS_ASSERTION(aOrigin.IsOrigin(), "Expect origin only here!");
   NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
   NS_ASSERTION(aCallback, "Null pointer!");
 }
 
 nsresult
 AsyncUsageRunnable::TakeShortcut()
 {
@@ -4237,32 +3791,27 @@ AsyncUsageRunnable::AddToUsage(QuotaMana
   rv = directory->Exists(&exists);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // If the directory exists then enumerate all the files inside, adding up
   // the sizes to get the final usage statistic.
   if (exists && !mCanceled) {
     bool initialized;
 
-    if (QuotaManager::IsTreatedAsPersistent(aPersistenceType, mOrigin)) {
+    if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
       initialized = aQuotaManager->mInitializedOrigins.Contains(mOrigin);
-    } else {
-      initialized = aQuotaManager->mTemporaryStorageInitialized;
-    }
-
-    nsCString* group;
-    if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
+
       if (!initialized) {
         rv = MaybeUpgradeOriginDirectory(directory);
         NS_ENSURE_SUCCESS(rv, rv);
       }
-
-      group = &mPersistentGroup;
-    } else {
-      group = &mTemporaryGroup;
+    }
+    else {
+      NS_ASSERTION(aPersistenceType == PERSISTENCE_TYPE_TEMPORARY, "Huh?");
+      initialized = aQuotaManager->mTemporaryStorageInitialized;
     }
 
     nsCOMPtr<nsISimpleEnumerator> entries;
     rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
     NS_ENSURE_SUCCESS(rv, rv);
 
     bool hasMore;
     while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
@@ -4302,20 +3851,20 @@ AsyncUsageRunnable::AddToUsage(QuotaMana
           return NS_ERROR_UNEXPECTED;
         }
         continue;
       }
 
       nsRefPtr<Client>& client = aQuotaManager->mClients[clientType];
 
       if (initialized) {
-        rv = client->GetUsageForOrigin(aPersistenceType, *group, mOrigin, this);
+        rv = client->GetUsageForOrigin(aPersistenceType, mGroup, mOrigin, this);
       }
       else {
-        rv = client->InitOrigin(aPersistenceType, *group, mOrigin, this);
+        rv = client->InitOrigin(aPersistenceType, mGroup, mOrigin, this);
       }
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   return NS_OK;
 }
 
@@ -4504,41 +4053,37 @@ FinalizeOriginEvictionRunnable::Run()
     }
 
     case IO: {
       AssertIsOnIOThread();
 
       AdvanceState();
 
       for (uint32_t index = 0; index < mOrigins.Length(); index++) {
-        const OriginParams& origin = mOrigins[index];
-
         quotaManager->OriginClearCompleted(
-                             origin.mPersistenceType,
-                             OriginOrPatternString::FromOrigin(origin.mOrigin));
+                            PERSISTENCE_TYPE_TEMPORARY,
+                            OriginOrPatternString::FromOrigin(mOrigins[index]));
       }
 
       if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
         NS_WARNING("Failed to dispatch to main thread!");
         return NS_ERROR_FAILURE;
       }
 
       return NS_OK;
     }
 
     case Complete: {
       NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
       for (uint32_t index = 0; index < mOrigins.Length(); index++) {
-        const OriginParams& origin = mOrigins[index];
-
         quotaManager->AllowNextSynchronizedOp(
-                             OriginOrPatternString::FromOrigin(origin.mOrigin),
-                             Nullable<PersistenceType>(origin.mPersistenceType),
-                             EmptyCString());
+                          OriginOrPatternString::FromOrigin(mOrigins[index]),
+                          Nullable<PersistenceType>(PERSISTENCE_TYPE_TEMPORARY),
+                          EmptyCString());
       }
 
       return NS_OK;
     }
 
     default:
       NS_ERROR("Unknown state value!");
       return NS_ERROR_UNEXPECTED;
@@ -4609,23 +4154,22 @@ SaveOriginAccessTimeRunnable::Run()
 {
   AssertIsOnIOThread();
 
   QuotaManager* quotaManager = QuotaManager::Get();
   NS_ASSERTION(quotaManager, "This should never fail!");
 
   nsCOMPtr<nsIFile> directory;
   nsresult rv =
-    quotaManager->GetDirectoryForOrigin(mPersistenceType, mOrigin,
+    quotaManager->GetDirectoryForOrigin(PERSISTENCE_TYPE_TEMPORARY, mOrigin,
                                         getter_AddRefs(directory));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIBinaryOutputStream> stream;
-  rv = GetDirectoryMetadataOutputStream(directory, true,
-                                        getter_AddRefs(stream));
+  rv = GetDirectoryMetadataStream(directory, true, getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // The origin directory may not exist anymore.
   if (stream) {
     rv = stream->Write64(mTimestamp);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
--- a/dom/quota/QuotaManager.h
+++ b/dom/quota/QuotaManager.h
@@ -16,16 +16,17 @@
 #include "mozilla/Mutex.h"
 
 #include "nsClassHashtable.h"
 #include "nsRefPtrHashtable.h"
 
 #include "ArrayCluster.h"
 #include "Client.h"
 #include "PersistenceType.h"
+#include "StoragePrivilege.h"
 
 #define QUOTA_MANAGER_CONTRACTID "@mozilla.org/dom/quota/manager;1"
 
 class nsIOfflineStorage;
 class nsIPrincipal;
 class nsIThread;
 class nsITimer;
 class nsIURI;
@@ -49,28 +50,16 @@ class GroupInfo;
 class GroupInfoPair;
 class OriginClearRunnable;
 class OriginInfo;
 class OriginOrPatternString;
 class QuotaObject;
 class ResetOrClearRunnable;
 struct SynchronizedOp;
 
-struct OriginParams
-{
-  OriginParams(PersistenceType aPersistenceType,
-               const nsACString& aOrigin)
-  : mOrigin(aOrigin)
-  , mPersistenceType(aPersistenceType)
-  { }
-
-  nsCString mOrigin;
-  PersistenceType mPersistenceType;
-};
-
 class QuotaManager MOZ_FINAL : public nsIQuotaManager,
                                public nsIObserver
 {
   friend class AsyncUsageRunnable;
   friend class CollectOriginsHelper;
   friend class FinalizeOriginEvictionRunnable;
   friend class GroupInfo;
   friend class OriginClearRunnable;
@@ -85,19 +74,16 @@ class QuotaManager MOZ_FINAL : public ns
     MozBrowser = 0,
     NotMozBrowser,
     IgnoreMozBrowser
   };
 
   typedef void
   (*WaitingOnStoragesCallback)(nsTArray<nsCOMPtr<nsIOfflineStorage> >&, void*);
 
-  typedef nsClassHashtable<nsCStringHashKey,
-                           nsTArray<nsIOfflineStorage*>> LiveStorageTable;
-
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIQUOTAMANAGER
   NS_DECL_NSIOBSERVER
 
   // Returns a non-owning reference.
   static QuotaManager*
   GetOrCreate();
@@ -131,17 +117,17 @@ public:
   UpdateOriginAccessTime(PersistenceType aPersistenceType,
                          const nsACString& aGroup,
                          const nsACString& aOrigin);
 
   void
   RemoveQuota();
 
   void
-  RemoveQuotaForTemporaryStorage();
+  RemoveQuotaForPersistenceType(PersistenceType);
 
   void
   RemoveQuotaForOrigin(PersistenceType aPersistenceType,
                        const nsACString& aGroup,
                        const nsACString& aOrigin)
   {
     MutexAutoLock lock(mQuotaMutex);
     LockedRemoveQuotaForOrigin(aPersistenceType, aGroup, aOrigin);
@@ -262,17 +248,17 @@ public:
   GetDirectoryForOrigin(PersistenceType aPersistenceType,
                         const nsACString& aASCIIOrigin,
                         nsIFile** aDirectory) const;
 
   nsresult
   EnsureOriginIsInitialized(PersistenceType aPersistenceType,
                             const nsACString& aGroup,
                             const nsACString& aOrigin,
-                            bool aHasUnlimStoragePerm,
+                            bool aTrackQuota,
                             nsIFile** aDirectory);
 
   void
   OriginClearCompleted(PersistenceType aPersistenceType,
                        const OriginOrPatternString& aOriginOrPattern);
 
   void
   ResetOrClearCompleted();
@@ -323,59 +309,40 @@ public:
                Client::Type aClientType,
                const nsAString& aName,
                nsACString& aDatabaseId);
 
   static nsresult
   GetInfoFromURI(nsIURI* aURI,
                  uint32_t aAppId,
                  bool aInMozBrowser,
-                 PersistenceType aPersistenceType,
                  nsACString* aGroup,
                  nsACString* aOrigin,
-                 bool* aIsApp,
-                 bool* aHasUnlimStoragePerm);
+                 StoragePrivilege* aPrivilege,
+                 PersistenceType* aDefaultPersistenceType);
 
   static nsresult
   GetInfoFromPrincipal(nsIPrincipal* aPrincipal,
-                       PersistenceType aPersistenceType,
                        nsACString* aGroup,
                        nsACString* aOrigin,
-                       bool* aIsApp,
-                       bool* aHasUnlimStoragePerm);
+                       StoragePrivilege* aPrivilege,
+                       PersistenceType* aDefaultPersistenceType);
 
   static nsresult
   GetInfoFromWindow(nsPIDOMWindow* aWindow,
-                    PersistenceType aPersistenceType,
                     nsACString* aGroup,
                     nsACString* aOrigin,
-                    bool* aIsApp,
-                    bool* aHasUnlimStoragePerm);
+                    StoragePrivilege* aPrivilege,
+                    PersistenceType* aDefaultPersistenceType);
 
   static void
   GetInfoForChrome(nsACString* aGroup,
                    nsACString* aOrigin,
-                   bool* aIsApp,
-                   bool* aHasUnlimStoragePerm);
-
-  static bool
-  IsTreatedAsPersistent(PersistenceType aPersistenceType,
-                        const nsACString& aOrigin);
-
-  static bool
-  IsTreatedAsTemporary(PersistenceType aPersistenceType,
-                       const nsACString& aOrigin)
-  {
-    return !IsTreatedAsPersistent(aPersistenceType, aOrigin);
-  }
-
-  static bool
-  IsQuotaEnforced(PersistenceType aPersistenceType,
-                  const nsACString& aOrigin,
-                  bool aHasUnlimStoragePerm);
+                   StoragePrivilege* aPrivilege,
+                   PersistenceType* aDefaultPersistenceType);
 
   static void
   ChromeOrigin(nsACString& aOrigin);
 
   static void
   GetOriginPatternString(uint32_t aAppId, bool aBrowserOnly,
                          const nsACString& aOrigin, nsAutoCString& _retval)
   {
@@ -441,76 +408,67 @@ private:
   FindSynchronizedOp(const nsACString& aPattern,
                      Nullable<PersistenceType> aPersistenceType,
                      const nsACString& aId);
 
   nsresult
   MaybeUpgradeIndexedDBDirectory();
 
   nsresult
-  InitializeRepository(PersistenceType aPersistenceType);
-
-  nsresult
   InitializeOrigin(PersistenceType aPersistenceType,
                    const nsACString& aGroup,
                    const nsACString& aOrigin,
-                   bool aHasUnlimStoragePerm,
+                   bool aTrackQuota,
                    int64_t aAccessTime,
                    nsIFile* aDirectory);
 
   nsresult
   ClearStoragesForApp(uint32_t aAppId, bool aBrowserOnly);
 
   void
   CheckTemporaryStorageLimits();
 
   // Collect inactive and the least recently used origins.
   uint64_t
   CollectOriginsForEviction(uint64_t aMinSizeToBeFreed,
                             nsTArray<OriginInfo*>& aOriginInfos);
 
   void
-  DeleteFilesForOrigin(PersistenceType aPersistenceType,
-                       const nsACString& aOrigin);
+  DeleteTemporaryFilesForOrigin(const nsACString& aOrigin);
 
   void
-  FinalizeOriginEviction(nsTArray<OriginParams>& aOrigins);
+  FinalizeOriginEviction(nsTArray<nsCString>& aOrigins);
 
   void
-  SaveOriginAccessTime(PersistenceType aPersistenceType,
-                       const nsACString& aOrigin,
-                       int64_t aTimestamp);
+  SaveOriginAccessTime(const nsACString& aOrigin, int64_t aTimestamp);
 
   void
   ReleaseIOThreadObjects()
   {
     AssertIsOnIOThread();
 
     for (uint32_t index = 0; index < Client::TYPE_MAX; index++) {
       mClients[index]->ReleaseIOThreadObjects();
     }
   }
 
   template <class OwnerClass>
   void
   AbortCloseStoragesFor(OwnerClass* aOwnerClass);
 
-  LiveStorageTable&
-  GetLiveStorageTable(PersistenceType aPersistenceType);
-
   static void
   GetOriginPatternString(uint32_t aAppId,
                          MozBrowserPatternFlag aBrowserFlag,
                          const nsACString& aOrigin,
                          nsAutoCString& _retval);
 
   static PLDHashOperator
-  RemoveQuotaForTemporaryStorageCallback(const nsACString& aKey,
-                                         nsAutoPtr<GroupInfoPair>& aValue,
-                                         void* aUserArg);
+  RemoveQuotaForPersistenceTypeCallback(const nsACString& aKey,
+                                        nsAutoPtr<GroupInfoPair>& aValue,
+                                        void* aUserArg);
 
   static PLDHashOperator
   RemoveQuotaCallback(const nsACString& aKey,
                       nsAutoPtr<GroupInfoPair>& aValue,
                       void* aUserArg);
 
   static PLDHashOperator
   RemoveQuotaForPatternCallback(const nsACString& aKey,
@@ -523,19 +481,19 @@ private:
                                 void* aUserArg);
 
   static PLDHashOperator
   GetAllTemporaryStorageOrigins(const nsACString& aKey,
                                 GroupInfoPair* aValue,
                                 void* aUserArg);
 
   static PLDHashOperator
-  AddLiveStorageOrigins(const nsACString& aKey,
-                        nsTArray<nsIOfflineStorage*>* aValue,
-                        void* aUserArg);
+  AddTemporaryStorageOrigins(const nsACString& aKey,
+                             ArrayCluster<nsIOfflineStorage*>* aValue,
+                             void* aUserArg);
 
   static PLDHashOperator
   GetInactiveTemporaryStorageOrigins(const nsACString& aKey,
                                      GroupInfoPair* aValue,
                                      void* aUserArg);
 
   // TLS storage index for the current thread's window.
   unsigned int mCurrentWindowIndex;
@@ -547,19 +505,16 @@ private:
   // A map of Windows to the corresponding quota helper.
   nsRefPtrHashtable<nsPtrHashKey<nsPIDOMWindow>,
                     CheckQuotaHelper> mCheckQuotaHelpers;
 
   // Maintains a list of live storages per origin.
   nsClassHashtable<nsCStringHashKey,
                    ArrayCluster<nsIOfflineStorage*> > mLiveStorages;
 
-  LiveStorageTable mPersistentLiveStorageTable;
-  LiveStorageTable mTemporaryLiveStorageTable;
-
   // Maintains a list of synchronized operatons that are in progress or queued.
   nsAutoTArray<nsAutoPtr<SynchronizedOp>, 5> mSynchronizedOps;
 
   // Thread on which IO is performed.
   nsCOMPtr<nsIThread> mIOThread;
 
   // A timer that gets activated at shutdown to ensure we close all storages.
   nsCOMPtr<nsITimer> mShutdownTimer;
--- a/dom/quota/QuotaObject.cpp
+++ b/dom/quota/QuotaObject.cpp
@@ -70,27 +70,27 @@ QuotaObject::UpdateSize(int64_t aSize)
   MutexAutoLock lock(quotaManager->mQuotaMutex);
 
   if (!mOriginInfo) {
     return;
   }
 
   GroupInfo* groupInfo = mOriginInfo->mGroupInfo;
 
-  if (mOriginInfo->IsTreatedAsTemporary()) {
+  if (groupInfo->IsForTemporaryStorage()) {
     quotaManager->mTemporaryStorageUsage -= mSize;
   }
   groupInfo->mUsage -= mSize;
   mOriginInfo->mUsage -= mSize;
 
   mSize = aSize;
 
   mOriginInfo->mUsage += mSize;
   groupInfo->mUsage += mSize;
-  if (mOriginInfo->IsTreatedAsTemporary()) {
+  if (groupInfo->IsForTemporaryStorage()) {
     quotaManager->mTemporaryStorageUsage += mSize;
   }
 }
 
 bool
 QuotaObject::MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount)
 {
   int64_t end = aOffset + aCount;
@@ -101,17 +101,17 @@ QuotaObject::MaybeAllocateMoreSpace(int6
   MutexAutoLock lock(quotaManager->mQuotaMutex);
 
   if (mSize >= end || !mOriginInfo) {
     return true;
   }
 
   GroupInfo* groupInfo = mOriginInfo->mGroupInfo;
 
-  if (mOriginInfo->IsTreatedAsPersistent()) {
+  if (groupInfo->IsForPersistentStorage()) {
     uint64_t newUsage = mOriginInfo->mUsage - mSize + end;
 
     if (newUsage > mOriginInfo->mLimit) {
       // This will block the thread, but it will also drop the mutex while
       // waiting. The mutex will be reacquired again when the waiting is
       // finished.
       if (!quotaManager->LockedQuotaIsLifted()) {
         return false;
@@ -130,17 +130,17 @@ QuotaObject::MaybeAllocateMoreSpace(int6
 
       nsCString group = mOriginInfo->mGroupInfo->mGroup;
       nsCString origin = mOriginInfo->mOrigin;
 
       mOriginInfo->LockedClearOriginInfos();
       NS_ASSERTION(!mOriginInfo,
                    "Should have cleared in LockedClearOriginInfos!");
 
-      quotaManager->LockedRemoveQuotaForOrigin(groupInfo->mPersistenceType,
+      quotaManager->LockedRemoveQuotaForOrigin(PERSISTENCE_TYPE_PERSISTENT,
                                                group, origin);
 
       // Some other thread could increase the size without blocking (increasing
       // the origin usage without hitting the limit), but no more than this one.
       NS_ASSERTION(mSize < end, "This shouldn't happen!");
 
       mSize = end;
 
@@ -151,37 +151,31 @@ QuotaObject::MaybeAllocateMoreSpace(int6
 
     groupInfo->mUsage = groupInfo->mUsage - mSize + end;
 
     mSize = end;
 
     return true;
   }
 
-  nsRefPtr<GroupInfo> complementaryGroupInfo =
-    groupInfo->mGroupInfoPair->LockedGetGroupInfo(
-      ComplementaryPersistenceType(groupInfo->mPersistenceType));
+  NS_ASSERTION(groupInfo->mPersistenceType == PERSISTENCE_TYPE_TEMPORARY,
+               "Huh?");
 
   uint64_t delta = end - mSize;
 
   uint64_t newUsage = mOriginInfo->mUsage + delta;
 
   // Temporary storage has no limit for origin usage (there's a group and the
   // global limit though).
 
   uint64_t newGroupUsage = groupInfo->mUsage + delta;
 
-  uint64_t groupUsage = groupInfo->LockedGetTemporaryUsage();
-  if (complementaryGroupInfo) {
-    groupUsage += complementaryGroupInfo->LockedGetTemporaryUsage();
-  }
-
   // Temporary storage has a hard limit for group usage (20 % of the global
   // limit).
-  if (groupUsage + delta > quotaManager->GetGroupLimit()) {
+  if (newGroupUsage > quotaManager->GetGroupLimit()) {
     return false;
   }
 
   uint64_t newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage +
                                       delta;
 
   if (newTemporaryStorageUsage > quotaManager->mTemporaryStorageLimit) {
     // This will block the thread without holding the lock while waitting.
@@ -195,62 +189,52 @@ QuotaObject::MaybeAllocateMoreSpace(int6
     }
 
     NS_ASSERTION(sizeToBeFreed >= delta, "Huh?");
 
     {
       MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
 
       for (uint32_t i = 0; i < originInfos.Length(); i++) {
-        OriginInfo* originInfo = originInfos[i];
-
-        quotaManager->DeleteFilesForOrigin(
-                                       originInfo->mGroupInfo->mPersistenceType,
-                                       originInfo->mOrigin);
+        quotaManager->DeleteTemporaryFilesForOrigin(originInfos[i]->mOrigin);
       }
     }
 
     // Relocked.
 
     NS_ASSERTION(mOriginInfo, "How come?!");
 
-    nsTArray<OriginParams> origins;
+    nsTArray<nsCString> origins;
     for (uint32_t i = 0; i < originInfos.Length(); i++) {
       OriginInfo* originInfo = originInfos[i];
 
       NS_ASSERTION(originInfo != mOriginInfo, "Deleted itself!");
 
-      PersistenceType persistenceType =
-        originInfo->mGroupInfo->mPersistenceType;
       nsCString group = originInfo->mGroupInfo->mGroup;
       nsCString origin = originInfo->mOrigin;
-      quotaManager->LockedRemoveQuotaForOrigin(persistenceType, group, origin);
+      quotaManager->LockedRemoveQuotaForOrigin(PERSISTENCE_TYPE_TEMPORARY,
+                                               group, origin);
 
 #ifdef DEBUG
       originInfos[i] = nullptr;
 #endif
 
-      origins.AppendElement(OriginParams(persistenceType, origin));
+      origins.AppendElement(origin);
     }
 
     // We unlocked and relocked several times so we need to recompute all the
     // essential variables and recheck the group limit.
 
     delta = end - mSize;
 
     newUsage = mOriginInfo->mUsage + delta;
 
     newGroupUsage = groupInfo->mUsage + delta;
 
-    groupUsage = groupInfo->LockedGetTemporaryUsage();
-    if (complementaryGroupInfo) {
-      groupUsage += complementaryGroupInfo->LockedGetTemporaryUsage();
-    }
-
-    if (groupUsage + delta > quotaManager->GetGroupLimit()) {
+    if (newGroupUsage > quotaManager->GetGroupLimit()) {
       // Unfortunately some other thread increased the group usage in the
       // meantime and we are not below the group limit anymore.
 
       // However, the origin eviction must be finalized in this case too.
       MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
 
       quotaManager->FinalizeOriginEviction(origins);
 
@@ -287,40 +271,26 @@ QuotaObject::MaybeAllocateMoreSpace(int6
   groupInfo->mUsage = newGroupUsage;
   quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;
 
   mSize = end;
 
   return true;
 }
 
-bool
-OriginInfo::IsTreatedAsPersistent() const
-{
-  return QuotaManager::IsTreatedAsPersistent(mGroupInfo->mPersistenceType,
-                                             mOrigin);
-}
-
-bool
-OriginInfo::IsTreatedAsTemporary() const
-{
-  return QuotaManager::IsTreatedAsTemporary(mGroupInfo->mPersistenceType,
-                                            mOrigin);
-}
-
 void
 OriginInfo::LockedDecreaseUsage(int64_t aSize)
 {
   AssertCurrentThreadOwnsQuotaMutex();
 
   mUsage -= aSize;
 
   mGroupInfo->mUsage -= aSize;
 
-  if (IsTreatedAsTemporary()) {
+  if (mGroupInfo->IsForTemporaryStorage()) {
     QuotaManager* quotaManager = QuotaManager::Get();
     NS_ASSERTION(quotaManager, "Shouldn't be null!");
 
     quotaManager->mTemporaryStorageUsage -= aSize;
   }
 }
 
 // static
@@ -360,34 +330,34 @@ GroupInfo::LockedAddOriginInfo(OriginInf
   AssertCurrentThreadOwnsQuotaMutex();
 
   NS_ASSERTION(!mOriginInfos.Contains(aOriginInfo),
                "Replacing an existing entry!");
   mOriginInfos.AppendElement(aOriginInfo);
 
   mUsage += aOriginInfo->mUsage;
 
-  if (aOriginInfo->IsTreatedAsTemporary()) {
+  if (IsForTemporaryStorage()) {
     QuotaManager* quotaManager = QuotaManager::Get();
     NS_ASSERTION(quotaManager, "Shouldn't be null!");
 
     quotaManager->mTemporaryStorageUsage += aOriginInfo->mUsage;
   }
 }
 
 void
 GroupInfo::LockedRemoveOriginInfo(const nsACString& aOrigin)
 {
   AssertCurrentThreadOwnsQuotaMutex();
 
   for (uint32_t index = 0; index < mOriginInfos.Length(); index++) {
     if (mOriginInfos[index]->mOrigin == aOrigin) {
       mUsage -= mOriginInfos[index]->mUsage;
 
-      if (mOriginInfos[index]->IsTreatedAsTemporary()) {
+      if (IsForTemporaryStorage()) {
         QuotaManager* quotaManager = QuotaManager::Get();
         NS_ASSERTION(quotaManager, "Shouldn't be null!");
 
         quotaManager->mTemporaryStorageUsage -= mOriginInfos[index]->mUsage;
       }
 
       mOriginInfos.RemoveElementAt(index);
 
@@ -397,108 +367,50 @@ GroupInfo::LockedRemoveOriginInfo(const 
 }
 
 void
 GroupInfo::LockedRemoveOriginInfos()
 {
   AssertCurrentThreadOwnsQuotaMutex();
 
   for (uint32_t index = mOriginInfos.Length(); index > 0; index--) {
-    OriginInfo* originInfo = mOriginInfos[index - 1];
+    mUsage -= mOriginInfos[index - 1]->mUsage;
 
-    mUsage -= originInfo->mUsage;
-
-    if (originInfo->IsTreatedAsTemporary()) {
+    if (IsForTemporaryStorage()) {
       QuotaManager* quotaManager = QuotaManager::Get();
       NS_ASSERTION(quotaManager, "Shouldn't be null!");
 
-      quotaManager->mTemporaryStorageUsage -= originInfo->mUsage;
+      quotaManager->mTemporaryStorageUsage -= mOriginInfos[index - 1]->mUsage;
     }
 
     mOriginInfos.RemoveElementAt(index - 1);
   }
 }
 
 void
 GroupInfo::LockedRemoveOriginInfosForPattern(const nsACString& aPattern)
 {
   AssertCurrentThreadOwnsQuotaMutex();
 
   for (uint32_t index = mOriginInfos.Length(); index > 0; index--) {
     if (PatternMatchesOrigin(aPattern, mOriginInfos[index - 1]->mOrigin)) {
       mUsage -= mOriginInfos[index - 1]->mUsage;
 
-      if (mOriginInfos[index - 1]->IsTreatedAsTemporary()) {
+      if (IsForTemporaryStorage()) {
         QuotaManager* quotaManager = QuotaManager::Get();
         NS_ASSERTION(quotaManager, "Shouldn't be null!");
 
         quotaManager->mTemporaryStorageUsage -= mOriginInfos[index - 1]->mUsage;
       }
 
       mOriginInfos.RemoveElementAt(index - 1);
     }
   }
 }
 
-uint64_t
-GroupInfo::LockedGetTemporaryUsage()
-{
-  uint64_t usage = 0;
-
-  for (uint32_t count = mOriginInfos.Length(), index = 0;
-       index < count;
-       index++) {
-    nsRefPtr<OriginInfo>& originInfo = mOriginInfos[index];
-
-    if (originInfo->IsTreatedAsTemporary()) {
-      usage += originInfo->mUsage;
-    }
-  }
-
-  return usage;
-}
-
-void
-GroupInfo::LockedGetTemporaryOriginInfos(nsTArray<OriginInfo*>* aOriginInfos)
-{
-  AssertCurrentThreadOwnsQuotaMutex();
-
-  for (uint32_t count = mOriginInfos.Length(), index = 0;
-       index < count;
-       index++) {
-    nsRefPtr<OriginInfo>& originInfo = mOriginInfos[index];
-
-    if (originInfo->IsTreatedAsTemporary()) {
-      aOriginInfos->AppendElement(originInfo);
-    }
-  }
-}
-
-void
-GroupInfo::LockedRemoveTemporaryOriginInfos()
-{
-  AssertCurrentThreadOwnsQuotaMutex();
-
-  QuotaManager* quotaManager = QuotaManager::Get();
-  MOZ_ASSERT(quotaManager);
-
-  for (uint32_t index = mOriginInfos.Length(); index > 0; index--) {
-    OriginInfo* originInfo = mOriginInfos[index - 1];
-    if (originInfo->IsTreatedAsTemporary()) {
-      MOZ_ASSERT(mUsage >= originInfo->mUsage);
-      mUsage -= originInfo->mUsage;
-
-      MOZ_ASSERT(quotaManager->mTemporaryStorageUsage >= originInfo->mUsage);
-      quotaManager->mTemporaryStorageUsage -= originInfo->mUsage;
-
-      mOriginInfos.RemoveElementAt(index - 1);
-    }
-  }
-}
-
 nsRefPtr<GroupInfo>&
 GroupInfoPair::GetGroupInfoForPersistenceType(PersistenceType aPersistenceType)
 {
   switch (aPersistenceType) {
     case PERSISTENCE_TYPE_PERSISTENT:
       return mPersistentStorageGroupInfo;
     case PERSISTENCE_TYPE_TEMPORARY:
       return mTemporaryStorageGroupInfo;
--- a/dom/quota/QuotaObject.h
+++ b/dom/quota/QuotaObject.h
@@ -86,22 +86,16 @@ public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OriginInfo)
 
   int64_t
   AccessTime() const
   {
     return mAccessTime;
   }
 
-  bool
-  IsTreatedAsPersistent() const;
-
-  bool
-  IsTreatedAsTemporary() const;
-
 private:
   // Private destructor, to discourage deletion outside of Release():
   ~OriginInfo()
   {
     MOZ_COUNT_DTOR(OriginInfo);
   }
 
   void
@@ -125,18 +119,18 @@ private:
 
   static PLDHashOperator
   ClearOriginInfoCallback(const nsAString& aKey,
                           QuotaObject* aValue, void* aUserArg);
 
   nsDataHashtable<nsStringHashKey, QuotaObject*> mQuotaObjects;
 
   GroupInfo* mGroupInfo;
-  const nsCString mOrigin;
-  const uint64_t mLimit;
+  nsCString mOrigin;
+  uint64_t mLimit;
   uint64_t mUsage;
   int64_t mAccessTime;
 };
 
 class OriginInfoLRUComparator
 {
 public:
   bool
@@ -156,26 +150,36 @@ public:
 class GroupInfo MOZ_FINAL
 {
   friend class GroupInfoPair;
   friend class OriginInfo;
   friend class QuotaManager;
   friend class QuotaObject;
 
 public:
-  GroupInfo(GroupInfoPair* aGroupInfoPair, PersistenceType aPersistenceType,
-            const nsACString& aGroup)
-  : mGroupInfoPair(aGroupInfoPair), mPersistenceType(aPersistenceType),
-    mGroup(aGroup), mUsage(0)
+  GroupInfo(PersistenceType aPersistenceType, const nsACString& aGroup)
+  : mPersistenceType(aPersistenceType), mGroup(aGroup), mUsage(0)
   {
     MOZ_COUNT_CTOR(GroupInfo);
   }
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GroupInfo)
 
+  bool
+  IsForPersistentStorage() const
+  {
+    return mPersistenceType == PERSISTENCE_TYPE_PERSISTENT;
+  }
+
+  bool
+  IsForTemporaryStorage() const
+  {
+    return mPersistenceType == PERSISTENCE_TYPE_TEMPORARY;
+  }
+
 private:
   // Private destructor, to discourage deletion outside of Release():
   ~GroupInfo()
   {
     MOZ_COUNT_DTOR(GroupInfo);
   }
 
   already_AddRefed<OriginInfo>
@@ -196,37 +200,26 @@ private:
   bool
   LockedHasOriginInfos()
   {
     AssertCurrentThreadOwnsQuotaMutex();
 
     return !mOriginInfos.IsEmpty();
   }
 
-  uint64_t
-  LockedGetTemporaryUsage();
-
-  void
-  LockedGetTemporaryOriginInfos(nsTArray<OriginInfo*>* aOriginInfos);
-
-  void
-  LockedRemoveTemporaryOriginInfos();
-
   nsTArray<nsRefPtr<OriginInfo> > mOriginInfos;
 
-  GroupInfoPair* mGroupInfoPair;
   PersistenceType mPersistenceType;
   nsCString mGroup;
   uint64_t mUsage;
 };
 
 class GroupInfoPair
 {
   friend class QuotaManager;
-  friend class QuotaObject;
 
 public:
   GroupInfoPair()
   {
     MOZ_COUNT_CTOR(GroupInfoPair);
   }
 
   ~GroupInfoPair()
new file mode 100644
--- /dev/null
+++ b/dom/quota/StoragePrivilege.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_quota_storageprivilege_h__
+#define mozilla_dom_quota_storageprivilege_h__
+
+#include "mozilla/dom/quota/QuotaCommon.h"
+
+BEGIN_QUOTA_NAMESPACE
+
+enum StoragePrivilege {
+  // Quota not tracked, persistence type is always "persistent".
+  Chrome,
+
+  // Quota tracked, persistence type can be either "persistent" or "temporary".
+  // The permission "defaul-persistent-storage" is used to determine the
+  // default persistence type.
+  Content,
+
+  // Only needed for IPC serialization helper, should never be used in code.
+  Invalid
+};
+
+END_QUOTA_NAMESPACE
+
+#endif // mozilla_dom_quota_storageprivilege_h__
--- a/dom/quota/moz.build
+++ b/dom/quota/moz.build
@@ -21,16 +21,17 @@ EXPORTS.mozilla.dom.quota += [
     'ArrayCluster.h',
     'Client.h',
     'FileStreams.h',
     'OriginOrPatternString.h',
     'PersistenceType.h',
     'QuotaCommon.h',
     'QuotaManager.h',
     'QuotaObject.h',
+    'StoragePrivilege.h',
     'UsageInfo.h',
     'Utilities.h',
 ]
 
 UNIFIED_SOURCES += [
     'CheckQuotaHelper.cpp',
     'FileStreams.cpp',
     'QuotaManager.cpp',