Bug 1314361: Part 7b - Strip addonId from existing quota storage origins. r?janv draft
authorKris Maglione <maglione.k@gmail.com>
Thu, 19 Jan 2017 15:18:32 -0800
changeset 464228 9dc3e600cf99f74383079ada6ef4e6a0ebafd181
parent 464227 14d6f1cd07182fda176d38b5f65b9fe264e84cf1
child 542884 c1a16d8a5422b5f58821dd8a0584285a4f30de7a
push id42306
push usermaglione.k@gmail.com
push dateFri, 20 Jan 2017 17:40:43 +0000
reviewersjanv
bugs1314361
milestone53.0a1
Bug 1314361: Part 7b - Strip addonId from existing quota storage origins. r?janv MozReview-Commit-ID: ABBe4LmbSmi
dom/indexedDB/ActorsParent.cpp
dom/indexedDB/test/unit/obsoleteOriginAttributes_profile.zip
dom/indexedDB/test/unit/test_obsoleteOriginAttributesUpgrade.js
dom/indexedDB/test/unit/xpcshell-parent-process.ini
dom/quota/ActorsParent.cpp
dom/quota/QuotaManager.h
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -158,17 +158,17 @@ class VersionChangeTransaction;
  ******************************************************************************/
 
 // If JS_STRUCTURED_CLONE_VERSION changes then we need to update our major
 // schema version.
 static_assert(JS_STRUCTURED_CLONE_VERSION == 8,
               "Need to update the major schema version.");
 
 // Major schema version. Bump for almost everything.
-const uint32_t kMajorSchemaVersion = 25;
+const uint32_t kMajorSchemaVersion = 26;
 
 // Minor schema version. Should almost always be 0 (maybe bump on release
 // branches if we have to).
 const uint32_t kMinorSchemaVersion = 0;
 
 // The schema version we store in the SQLite database is a (signed) 32-bit
 // integer. The major version is left-shifted 4 bits so the max value is
 // 0xFFFFFFF. The minor version occupies the lower 4 bits and its max is 0xF.
@@ -4126,16 +4126,103 @@ UpgradeSchemaFrom24_0To25_0(mozIStorageC
   nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(25, 0));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
+class StripObsoleteOriginAttributesFunction final
+  : public mozIStorageFunction
+{
+public:
+  NS_DECL_ISUPPORTS
+
+private:
+  ~StripObsoleteOriginAttributesFunction()
+  { }
+
+  NS_IMETHOD
+  OnFunctionCall(mozIStorageValueArray* aArguments,
+                 nsIVariant** aResult) override
+  {
+    MOZ_ASSERT(aArguments);
+    MOZ_ASSERT(aResult);
+
+    PROFILER_LABEL("IndexedDB",
+                   "StripObsoleteOriginAttributesFunction::OnFunctionCall",
+                   js::ProfileEntry::Category::STORAGE);
+
+    nsCString origin;
+    nsresult rv = aArguments->GetUTF8String(0, origin);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    // Deserialize and re-serialize to automatically drop any obsolete origin
+    // attributes.
+    OriginAttributes oa;
+    nsCString newOrigin;
+    bool ok = oa.PopulateFromOrigin(origin, newOrigin);
+    if (NS_WARN_IF(!ok)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    nsAutoCString newSuffix;
+    oa.CreateSuffix(newSuffix);
+    newOrigin.Append(newSuffix);
+
+    nsCOMPtr<nsIVariant> result = new mozilla::storage::TextVariant(
+      NS_ConvertUTF8toUTF16(newOrigin));
+
+    result.forget(aResult);
+    return NS_OK;
+  }
+};
+
+nsresult
+UpgradeSchemaFrom25_0To26_0(mozIStorageConnection* aConnection)
+{
+  AssertIsOnIOThread();
+  MOZ_ASSERT(aConnection);
+
+  PROFILER_LABEL("IndexedDB",
+                 "UpgradeSchemaFrom25_0To26_0",
+                 js::ProfileEntry::Category::STORAGE);
+
+  NS_NAMED_LITERAL_CSTRING(functionName, "strip_obsolete_attributes");
+
+  nsCOMPtr<mozIStorageFunction> stripObsoleteAttributes = new StripObsoleteOriginAttributesFunction();
+
+  nsresult rv = aConnection->CreateFunction(functionName, 1, stripObsoleteAttributes);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "UPDATE DATABASE "
+    "  SET origin = strip_obsolete_attributes(origin) "
+    "  WHERE origin LIKE '%^%' "
+    ";"
+  ));
+
+  rv = aConnection->RemoveFunction(functionName);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = aConnection->SetSchemaVersion(MakeSchemaVersion(26, 0));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
 nsresult
 GetDatabaseFileURL(nsIFile* aDatabaseFile,
                    PersistenceType aPersistenceType,
                    const nsACString& aGroup,
                    const nsACString& aOrigin,
                    uint32_t aTelemetryId,
                    nsIFileURL** aResult)
 {
@@ -4632,17 +4719,17 @@ CreateStorageConnection(nsIFile* aDBFile
       }
 
       rv = stmt->Execute();
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     } else  {
       // This logic needs to change next time we change the schema!
-      static_assert(kSQLiteSchemaVersion == int32_t((25 << 4) + 0),
+      static_assert(kSQLiteSchemaVersion == int32_t((26 << 4) + 0),
                     "Upgrade function needed due to schema version increase.");
 
       while (schemaVersion != kSQLiteSchemaVersion) {
         if (schemaVersion == 4) {
           rv = UpgradeSchemaFrom4To5(connection);
         } else if (schemaVersion == 5) {
           rv = UpgradeSchemaFrom5To6(connection);
         } else if (schemaVersion == 6) {
@@ -4680,16 +4767,18 @@ CreateStorageConnection(nsIFile* aDBFile
         } else if (schemaVersion == MakeSchemaVersion(21, 0)) {
           rv = UpgradeSchemaFrom21_0To22_0(connection);
         } else if (schemaVersion == MakeSchemaVersion(22, 0)) {
           rv = UpgradeSchemaFrom22_0To23_0(connection, aOrigin);
         } else if (schemaVersion == MakeSchemaVersion(23, 0)) {
           rv = UpgradeSchemaFrom23_0To24_0(connection);
         } else if (schemaVersion == MakeSchemaVersion(24, 0)) {
           rv = UpgradeSchemaFrom24_0To25_0(connection);
+        } else if (schemaVersion == MakeSchemaVersion(25, 0)) {
+          rv = UpgradeSchemaFrom25_0To26_0(connection);
         } else {
           IDB_WARNING("Unable to open IndexedDB database, no upgrade path is "
                       "available!");
           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
         }
 
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
@@ -19327,16 +19416,17 @@ AutoProgressHandler::OnProgress(mozIStor
 }
 
 /*******************************************************************************
  * Local class implementations
  ******************************************************************************/
 
 NS_IMPL_ISUPPORTS(CompressDataBlobsFunction, mozIStorageFunction)
 NS_IMPL_ISUPPORTS(EncodeKeysFunction, mozIStorageFunction)
+NS_IMPL_ISUPPORTS(StripObsoleteOriginAttributesFunction, mozIStorageFunction);
 
 #if !defined(MOZ_B2G)
 
 nsresult
 UpgradeFileIdsFunction::Init(nsIFile* aFMDirectory,
                              mozIStorageConnection* aConnection)
 {
   // This file manager doesn't need real origin info, etc. The only purpose is
new file mode 100644
index 0000000000000000000000000000000000000000..f05ff4f24aa119ddc415fd067fc96079b6e27056
GIT binary patch
literal 11853
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
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_obsoleteOriginAttributesUpgrade.js
@@ -0,0 +1,71 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+Components.utils.import("resource://gre/modules/FileUtils.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+var testGenerator = testSteps();
+
+function* testSteps()
+{
+  const openParams = [
+    { url: "moz-extension://8ea6d31b-917c-431f-a204-15b95e904d4f",
+      dbName: "Hello.", dbVersion: 1 },
+    { url: "moz-extension://8ea6d31b-917c-431f-a204-15b95e904d4f",
+      dbName: "Hello.", dbOptions: { version: 1, storage: "temporary" } },
+    { url: "moz-extension://8ea6d31b-917c-431f-a204-15b95e904d4f",
+      dbName: "Hello.", dbOptions: { version: 1, storage: "permanent" } },
+  ];
+
+  function openDatabase(params) {
+    let uri = Services.io.newURI(params.url);
+    let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
+    return indexedDB.openForPrincipal(principal, params.dbName,
+                                      params.dbVersion);
+  }
+
+  clearAllDatabases(continueToNextStepSync);
+  yield;
+
+  installPackagedProfile("obsoleteOriginAttributes_profile");
+
+  for (let params of openParams) {
+    let request = openDatabase(params);
+    request.onerror = errorHandler;
+    request.onupgradeneeded = unexpectedSuccessHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield;
+
+    is(event.type, "success", "Correct event type");
+  }
+
+  resetAllDatabases(continueToNextStepSync);
+  yield;
+
+  for (let params of openParams) {
+    let request = openDatabase(params);
+    request.onerror = errorHandler;
+    request.onupgradeneeded = unexpectedSuccessHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield;
+
+    is(event.type, "success", "Correct event type");
+  }
+
+  const OLD_NAME = "moz-extension+++8ea6d31b-917c-431f-a204-15b95e904d4f^addonId=indexedDB-test%40kmaglione.mozilla.com";
+  const NEW_NAME = "moz-extension+++8ea6d31b-917c-431f-a204-15b95e904d4f";
+
+  for (let subdir of ["default", "temporary", "permanent"]) {
+    let file = FileUtils.getFile("ProfD", ["storage", subdir, OLD_NAME]);
+    ok(!file.exists(), `Old ${subdir} storage directory should not exist`);
+
+    file.leafName = NEW_NAME;
+    ok(file.exists(), `New ${subdir} storage directory should exist`);
+  }
+
+  finishTest();
+  yield;
+}
+
--- a/dom/indexedDB/test/unit/xpcshell-parent-process.ini
+++ b/dom/indexedDB/test/unit/xpcshell-parent-process.ini
@@ -8,16 +8,17 @@ head = xpcshell-head-parent-process.js
 tail =
 skip-if = toolkit == 'gonk'
 support-files =
   bug1056939_profile.zip
   defaultStorageUpgrade_profile.zip
   idbSubdirUpgrade1_profile.zip
   idbSubdirUpgrade2_profile.zip
   mutableFileUpgrade_profile.zip
+  obsoleteOriginAttributes_profile.zip
   oldDirectories_profile.zip
   GlobalObjectsChild.js
   GlobalObjectsComponent.js
   GlobalObjectsComponent.manifest
   GlobalObjectsModule.jsm
   GlobalObjectsSandbox.js
   metadata2Restore_profile.zip
   metadataRestore_profile.zip
@@ -28,16 +29,17 @@ support-files =
   storagePersistentUpgrade_profile.zip
   wasm_recompile_profile.zip
   xpcshell-shared.ini
 
 [include:xpcshell-shared.ini]
 
 [test_bad_origin_directory.js]
 skip-if = release_or_beta
+[test_obsoleteOriginAttributesUpgrade.js]
 [test_blob_file_backed.js]
 [test_bug1056939.js]
 [test_cleanup_transaction.js]
 [test_database_close_without_onclose.js]
 [test_database_onclose.js]
 [test_defaultStorageUpgrade.js]
 [test_file_copy_failure.js]
 [test_idbSubdirUpgrade.js]
--- a/dom/quota/ActorsParent.cpp
+++ b/dom/quota/ActorsParent.cpp
@@ -116,17 +116,17 @@ namespace {
 
 /*******************************************************************************
  * Constants
  ******************************************************************************/
 
 const uint32_t kSQLitePageSizeOverride = 512;
 
 // Major storage version. Bump for backwards-incompatible changes.
-const uint32_t kMajorStorageVersion = 1;
+const uint32_t kMajorStorageVersion = 2;
 
 // Minor storage version. Bump for backwards-compatible changes.
 const uint32_t kMinorStorageVersion = 0;
 
 // The storage version we store in the SQLite database is a (signed) 32-bit
 // integer. The major version is left-shifted 16 bits so the max value is
 // 0xFFFF. The minor version occupies the lower 16 bits and its max is 0xFFFF.
 static_assert(kMajorStorageVersion <= 0xFFFF,
@@ -175,24 +175,22 @@ enum AppId {
 // origin.
 #define METADATA_FILE_NAME ".metadata"
 #define METADATA_V2_FILE_NAME ".metadata-v2"
 
 /******************************************************************************
  * SQLite functions
  ******************************************************************************/
 
-#if 0
 int32_t
 MakeStorageVersion(uint32_t aMajorStorageVersion,
                    uint32_t aMinorStorageVersion)
 {
   return int32_t((aMajorStorageVersion << 16) + aMinorStorageVersion);
 }
-#endif
 
 uint32_t
 GetMajorStorageVersion(int32_t aStorageVersion)
 {
   return uint32_t(aStorageVersion >> 16);
 
 }
 
@@ -1540,16 +1538,40 @@ public:
   nsresult
   RestoreMetadata2File();
 
 private:
   virtual nsresult
   DoProcessOriginDirectories();
 };
 
+class UpdateDirectoryMetadataOriginHelper final
+  : public StorageDirectoryHelper
+{
+public:
+  explicit UpdateDirectoryMetadataOriginHelper(nsIFile* aDirectory)
+    : StorageDirectoryHelper(aDirectory)
+  { }
+
+  nsresult
+  UpgradeMetadataFiles();
+
+private:
+  nsresult
+  GetDirectoryMetadata2(nsIFile* aDirectory,
+                        int64_t* aTimestamp,
+                        nsACString& aSuffix,
+                        nsACString& aGroup,
+                        nsACString& aOrigin,
+                        bool* aIsApp);
+
+  virtual nsresult
+  DoProcessOriginDirectories() override;
+};
+
 class OriginKey : public nsAutoCString
 {
 public:
   OriginKey(PersistenceType aPersistenceType,
             const nsACString& aOrigin)
   {
     PersistenceTypeToText(aPersistenceType, *this);
     Append(':');
@@ -4184,45 +4206,60 @@ QuotaManager::UpgradeStorageFrom0_0To1_0
   rv = aConnection->SetSchemaVersion(kStorageVersion);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
-#if 0
 nsresult
 QuotaManager::UpgradeStorageFrom1_0To2_0(mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
   nsresult rv;
-
-#ifdef DEBUG
-  {
-    int32_t storageVersion;
-    rv = aConnection->GetSchemaVersion(&storageVersion);
+  for (const PersistenceType persistenceType : kAllPersistenceTypes) {
+    nsCOMPtr<nsIFile> directory =
+      do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    rv = directory->InitWithPath(GetStoragePath(persistenceType));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    MOZ_ASSERT(storageVersion == MakeStorageVersion(1, 0));
-  }
-#endif
+    bool exists;
+    rv = directory->Exists(&exists);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    if (!exists) {
+      continue;
+    }
+
+    RefPtr<UpdateDirectoryMetadataOriginHelper> helper =
+      new UpdateDirectoryMetadataOriginHelper(directory);
+
+    rv = helper->UpgradeMetadataFiles();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
 
   rv = aConnection->SetSchemaVersion(MakeStorageVersion(2, 0));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
-#endif
 
 nsresult
 QuotaManager::EnsureStorageIsInitialized()
 {
   AssertIsOnIOThread();
 
   if (mStorageInitialized) {
     return NS_OK;
@@ -4351,26 +4388,24 @@ QuotaManager::EnsureStorageIsInitialized
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       MOZ_ASSERT(NS_SUCCEEDED(connection->GetSchemaVersion(&storageVersion)));
       MOZ_ASSERT(storageVersion == kStorageVersion);
     } else {
       // This logic needs to change next time we change the storage!
-      static_assert(kStorageVersion == int32_t((1 << 16) + 0),
+      static_assert(kStorageVersion == int32_t((2 << 16) + 0),
                     "Upgrade function needed due to storage version increase.");
 
       while (storageVersion != kStorageVersion) {
         if (storageVersion == 0) {
           rv = UpgradeStorageFrom0_0To1_0(connection);
-#if 0
         } else if (storageVersion == MakeStorageVersion(1, 0)) {
           rv = UpgradeStorageFrom1_0To2_0(connection);
-#endif
         } else {
           NS_WARNING("Unable to initialize storage, no upgrade path is "
                      "available!");
           return NS_ERROR_FAILURE;
         }
 
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
@@ -7711,11 +7746,231 @@ RestoreDirectoryMetadata2Helper::DoProce
                                          originProps.mIsApp);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
+nsresult
+UpdateDirectoryMetadataOriginHelper::GetDirectoryMetadata2(nsIFile* aDirectory,
+                                                           int64_t* aTimestamp,
+                                                           nsACString& aSuffix,
+                                                           nsACString& aGroup,
+                                                           nsACString& aOrigin,
+                                                           bool* aIsApp)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  MOZ_ASSERT(aDirectory);
+  MOZ_ASSERT(aTimestamp);
+  MOZ_ASSERT(aIsApp);
+
+  nsCOMPtr<nsIBinaryInputStream> binaryStream;
+  nsresult rv = GetBinaryInputStream(aDirectory,
+                                     NS_LITERAL_STRING(METADATA_V2_FILE_NAME),
+                                     getter_AddRefs(binaryStream));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  uint64_t timestamp;
+  rv = binaryStream->Read64(&timestamp);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool persisted;
+  rv = binaryStream->ReadBoolean(&persisted);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  uint32_t reservedData1;
+  rv = binaryStream->Read32(&reservedData1);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  uint32_t reservedData2;
+  rv = binaryStream->Read32(&reservedData2);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCString suffix;
+  rv = binaryStream->ReadCString(suffix);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCString group;
+  rv = binaryStream->ReadCString(group);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCString origin;
+  rv = binaryStream->ReadCString(origin);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool isApp;
+  rv = binaryStream->ReadBoolean(&isApp);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  *aTimestamp = timestamp;
+  aSuffix = suffix;
+  aGroup = group;
+  aOrigin = origin;
+  *aIsApp = isApp;
+  return NS_OK;
+}
+
+nsresult
+UpdateDirectoryMetadataOriginHelper::UpgradeMetadataFiles()
+{
+  AssertIsOnIOThread();
+
+  bool exists;
+  nsresult rv = mDirectory->Exists(&exists);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  if (!exists) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsISimpleEnumerator> entries;
+  rv = mDirectory->GetDirectoryEntries(getter_AddRefs(entries));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  bool hasMore;
+  while (NS_SUCCEEDED(entries->HasMoreElements(&hasMore)) && hasMore) {
+    nsCOMPtr<nsISupports> entry;
+    rv = entries->GetNext(getter_AddRefs(entry));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    nsCOMPtr<nsIFile> originDir = do_QueryInterface(entry);
+    MOZ_ASSERT(originDir);
+
+    bool isDirectory;
+    rv = originDir->IsDirectory(&isDirectory);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    if (!isDirectory) {
+      nsString leafName;
+      rv = originDir->GetLeafName(leafName);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      if (!leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
+        QM_WARNING("Something (%s) in the storage directory that doesn't belong!",
+                   NS_ConvertUTF16toUTF8(leafName).get());
+
+      }
+      continue;
+    }
+
+    OriginProps* originProps;
+    rv = AddOriginDirectory(originDir, &originProps);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    nsresult rv = GetDirectoryMetadata2(originDir,
+                                        &originProps->mTimestamp,
+                                        originProps->mSuffix,
+                                        originProps->mGroup,
+                                        originProps->mOrigin,
+                                        &originProps->mIsApp);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      // This isn't a fatal error. If we fail to read the metadata file, we fall
+      // back to the metadata extracted from the directory name.
+      QM_WARNING("Origin directory %s is missing metadata file",
+                 originProps->mOrigin.get());
+    }
+  }
+
+  if (mOriginProps.IsEmpty()) {
+    return NS_OK;
+  }
+
+  rv = ProcessOriginDirectories();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+nsresult
+UpdateDirectoryMetadataOriginHelper::DoProcessOriginDirectories()
+{
+  AssertIsOnIOThread();
+
+  for (auto& originProps : mOriginProps) {
+    nsresult rv;
+
+    // Attempt to rename the directory to the new origin.
+    nsAutoCString newOrigin(originProps.mOrigin);
+    SanitizeOriginString(newOrigin);
+
+    NS_ConvertUTF8toUTF16 newLeafName(newOrigin);
+
+    nsString oldLeafName;
+    rv = originProps.mDirectory->GetLeafName(oldLeafName);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    if (oldLeafName == newLeafName) {
+      continue;
+    }
+
+    nsCOMPtr<nsIFile> newFile;
+    rv = originProps.mDirectory->GetParent(getter_AddRefs(newFile));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    rv = newFile->Append(newLeafName);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    bool exists;
+    rv = newFile->Exists(&exists);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    if (exists) {
+      QM_WARNING("Origin directory with addonId attribute (%s) clashes with existing origin (%s)",
+                 NS_ConvertUTF16toUTF8(oldLeafName).get(), newOrigin.get());
+      continue;
+    }
+
+    rv = CreateDirectoryMetadata(originProps.mDirectory,
+                                 originProps.mTimestamp,
+                                 originProps.mSuffix,
+                                 originProps.mGroup,
+                                 originProps.mOrigin,
+                                 originProps.mIsApp);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    rv = CreateDirectoryMetadata2(originProps.mDirectory,
+                                  originProps.mTimestamp,
+                                  originProps.mSuffix,
+                                  originProps.mGroup,
+                                  originProps.mOrigin,
+                                  originProps.mIsApp);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    rv = originProps.mDirectory->RenameTo(nullptr, newLeafName);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  return NS_OK;
+}
+
 } // namespace quota
 } // namespace dom
 } // namespace mozilla
--- a/dom/quota/QuotaManager.h
+++ b/dom/quota/QuotaManager.h
@@ -452,20 +452,18 @@ private:
   MaybeUpgradePersistentStorageDirectory();
 
   nsresult
   MaybeRemoveOldDirectories();
 
   nsresult
   UpgradeStorageFrom0_0To1_0(mozIStorageConnection* aConnection);
 
-#if 0
   nsresult
   UpgradeStorageFrom1_0To2_0(mozIStorageConnection* aConnection);
-#endif
 
   nsresult
   InitializeRepository(PersistenceType aPersistenceType);
 
   nsresult
   InitializeOrigin(PersistenceType aPersistenceType,
                    const nsACString& aGroup,
                    const nsACString& aOrigin,