Bug 1690291 - Handle NS_ERROR_STORAGE_IOERR when opening a database like NS_ERROR_FILE_CORRUPTED. r=dom-workers-and-storage-reviewers,asuth
authorSimon Giesecke <sgiesecke@mozilla.com>
Thu, 04 Feb 2021 11:43:22 +0000
changeset 565996 acb6ae451d74717759ac1bd1e00bd9f0005a16d9
parent 565995 9203893c869667cd73e060266a1f509b5ce97a62
child 565997 9a0de0e7548f1eaf6152f98034febc49591f8796
push id135707
push usersgiesecke@mozilla.com
push dateThu, 04 Feb 2021 12:15:53 +0000
treeherderautoland@acb6ae451d74 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdom-workers-and-storage-reviewers, asuth
bugs1690291
milestone87.0a1
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
Bug 1690291 - Handle NS_ERROR_STORAGE_IOERR when opening a database like NS_ERROR_FILE_CORRUPTED. r=dom-workers-and-storage-reviewers,asuth Differential Revision: https://phabricator.services.mozilla.com/D103898
dom/cache/DBAction.cpp
dom/indexedDB/ActorsParent.cpp
dom/localstorage/ActorsParent.cpp
dom/quota/ActorsParent.cpp
dom/quota/QuotaCommon.h
--- a/dom/cache/DBAction.cpp
+++ b/dom/cache/DBAction.cpp
@@ -21,16 +21,17 @@
 #include "nsIFileURL.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla::dom::cache {
 
 using mozilla::dom::quota::AssertIsOnIOThread;
 using mozilla::dom::quota::Client;
 using mozilla::dom::quota::CloneFileAndAppend;
+using mozilla::dom::quota::IsDatabaseCorruptionError;
 using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
 using mozilla::dom::quota::PersistenceType;
 
 namespace {
 
 nsresult WipeDatabase(const QuotaInfo& aQuotaInfo, nsIFile& aDBFile) {
   CACHE_TRY_INSPECT(
       const auto& dbDir,
@@ -172,17 +173,17 @@ Result<nsCOMPtr<mozIStorageConnection>, 
   CACHE_TRY_UNWRAP(
       auto conn,
       MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>,
                                  storageService, OpenDatabaseWithFileURL,
                                  dbFileUrl, ""_ns)
           .orElse([&aQuotaInfo, &aDBFile, &storageService,
                    &dbFileUrl](const nsresult rv)
                       -> Result<nsCOMPtr<mozIStorageConnection>, nsresult> {
-            if (rv == NS_ERROR_FILE_CORRUPTED) {
+            if (IsDatabaseCorruptionError(rv)) {
               NS_WARNING(
                   "Cache database corrupted. Recreating empty database.");
 
               // There is nothing else we can do to recover.  Also, this data
               // can be deleted by QuotaManager at any time anyways.
               CACHE_TRY(WipeDatabase(aQuotaInfo, aDBFile));
 
               CACHE_TRY_RETURN(MOZ_TO_RESULT_INVOKE_TYPED(
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -845,17 +845,17 @@ CreateStorageConnection(nsIFile& aDBFile
           .map([](auto connection) -> nsCOMPtr<mozIStorageConnection> {
             return std::move(connection).unwrapBasePtr();
           })
           .orElse([&aName](nsresult aValue)
                       -> Result<nsCOMPtr<mozIStorageConnection>, nsresult> {
             // If we're just opening the database during origin initialization,
             // then we don't want to erase any files. The failure here will fail
             // origin initialization too.
-            if (aValue != NS_ERROR_FILE_CORRUPTED || aName.IsVoid()) {
+            if (!IsDatabaseCorruptionError(aValue) || aName.IsVoid()) {
               return Err(aValue);
             }
 
             return nsCOMPtr<mozIStorageConnection>();
           }));
 
   if (!connection) {
     // XXX Shouldn't we also update quota usage?
--- a/dom/localstorage/ActorsParent.cpp
+++ b/dom/localstorage/ActorsParent.cpp
@@ -461,17 +461,17 @@ Result<nsCOMPtr<mozIStorageConnection>, 
 
   LS_TRY_UNWRAP(
       auto connection,
       MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>,
                                  storageService, OpenDatabase, &aDBFile)
           .orElse([&aUsageFile, &aDBFile, &aCorruptedFileHandler,
                    &storageService](const nsresult rv)
                       -> Result<nsCOMPtr<mozIStorageConnection>, nsresult> {
-            if (rv == NS_ERROR_FILE_CORRUPTED) {
+            if (IsDatabaseCorruptionError(rv)) {
               // Remove the usage file first (it might not exist at all due
               // to corrupted state, which is ignored here).
               LS_TRY(ToResult(aUsageFile.Remove(false))
                          .orElse([](const nsresult rv) -> Result<Ok, nsresult> {
                            if (rv == NS_ERROR_FILE_NOT_FOUND ||
                                rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
                              return Ok{};
                            }
@@ -673,17 +673,17 @@ CreateArchiveStorageConnection(const nsA
                                      MOZ_STORAGE_SERVICE_CONTRACTID));
 
   LS_TRY_UNWRAP(
       auto connection,
       MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>, ss,
                                  OpenUnsharedDatabase, archiveFile)
           .orElse([](const nsresult rv)
                       -> Result<nsCOMPtr<mozIStorageConnection>, nsresult> {
-            if (rv == NS_ERROR_FILE_CORRUPTED) {
+            if (IsDatabaseCorruptionError(rv)) {
               // Don't throw an error, leave a corrupted ls-archive database as
               // it is.
               return nsCOMPtr<mozIStorageConnection>{};
             }
 
             return Err(rv);
           }));
 
@@ -809,17 +809,17 @@ Result<nsCOMPtr<mozIStorageConnection>, 
                                      MOZ_STORAGE_SERVICE_CONTRACTID));
 
   LS_TRY_UNWRAP(
       auto connection,
       MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>, ss,
                                  OpenUnsharedDatabase, shadowFile)
           .orElse([&shadowFile, &ss](const nsresult rv)
                       -> Result<nsCOMPtr<mozIStorageConnection>, nsresult> {
-            if (rv == NS_ERROR_FILE_CORRUPTED) {
+            if (IsDatabaseCorruptionError(rv)) {
               LS_TRY(shadowFile->Remove(false));
 
               LS_TRY_RETURN(MOZ_TO_RESULT_INVOKE_TYPED(
                   nsCOMPtr<mozIStorageConnection>, ss, OpenUnsharedDatabase,
                   shadowFile));
             }
 
             return Err(rv);
--- a/dom/quota/ActorsParent.cpp
+++ b/dom/quota/ActorsParent.cpp
@@ -490,17 +490,17 @@ Result<nsCOMPtr<mozIStorageConnection>, 
 
   QM_TRY_INSPECT(
       const auto& connection,
       MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>,
                                  aStorageService, OpenUnsharedDatabase,
                                  &aWebAppsStoreFile)
           .orElse([](const nsresult rv)
                       -> Result<nsCOMPtr<mozIStorageConnection>, nsresult> {
-            if (rv == NS_ERROR_FILE_CORRUPTED) {
+            if (IsDatabaseCorruptionError(rv)) {
               // Don't throw an error, leave a corrupted webappsstore database
               // as it is.
               return nsCOMPtr<mozIStorageConnection>{};
             }
 
             return Err(rv);
           }));
 
@@ -5952,17 +5952,17 @@ QuotaManager::CreateLocalStorageArchiveC
                                        MOZ_STORAGE_SERVICE_CONTRACTID));
 
     QM_TRY_UNWRAP(
         auto connection,
         MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>, ss,
                                    OpenUnsharedDatabase, lsArchiveFile)
             .orElse([&removed, &lsArchiveFile, &ss](const nsresult rv)
                         -> Result<nsCOMPtr<mozIStorageConnection>, nsresult> {
-              if (!removed && rv == NS_ERROR_FILE_CORRUPTED) {
+              if (!removed && IsDatabaseCorruptionError(rv)) {
                 QM_TRY(lsArchiveFile->Remove(false));
 
                 removed = true;
 
                 QM_TRY_RETURN(MOZ_TO_RESULT_INVOKE_TYPED(
                     nsCOMPtr<mozIStorageConnection>, ss, OpenUnsharedDatabase,
                     lsArchiveFile));
               }
@@ -6131,18 +6131,18 @@ nsresult QuotaManager::EnsureStorageIsIn
 
   QM_TRY_INSPECT(const auto& ss, ToResultGet<nsCOMPtr<mozIStorageService>>(
                                      MOZ_SELECT_OVERLOAD(do_GetService),
                                      MOZ_STORAGE_SERVICE_CONTRACTID));
 
   QM_TRY_UNWRAP(auto connection,
                 MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>, ss,
                                            OpenUnsharedDatabase, storageFile)
-                    .orElse(ErrToOkOrErr<NS_ERROR_FILE_CORRUPTED, nullptr,
-                                         nsCOMPtr<mozIStorageConnection>>));
+                    .orElse(FilterDatabaseCorruptionError<
+                            nullptr, nsCOMPtr<mozIStorageConnection>>));
 
   if (!connection) {
     // Nuke the database file.
     QM_TRY(storageFile->Remove(false));
 
     QM_TRY_UNWRAP(connection, MOZ_TO_RESULT_INVOKE_TYPED(
                                   nsCOMPtr<mozIStorageConnection>, ss,
                                   OpenUnsharedDatabase, storageFile));
--- a/dom/quota/QuotaCommon.h
+++ b/dom/quota/QuotaCommon.h
@@ -1215,13 +1215,26 @@ auto ReduceEachFileAtomicCancelable(nsIF
         }
 
         QM_TRY_RETURN(MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<nsIFile>, entries,
                                                  GetNextFile));
       },
       std::move(aInit), aBody);
 }
 
+constexpr bool IsDatabaseCorruptionError(const nsresult aRv) {
+  return aRv == NS_ERROR_FILE_CORRUPTED || aRv == NS_ERROR_STORAGE_IOERR;
+}
+
+template <auto SuccessValue, typename V = decltype(SuccessValue)>
+auto FilterDatabaseCorruptionError(const nsresult aValue)
+    -> Result<V, nsresult> {
+  if (IsDatabaseCorruptionError(aValue)) {
+    return V{SuccessValue};
+  }
+  return Err(aValue);
+}
+
 }  // namespace quota
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_quota_quotacommon_h__