mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-26 20:30:41 +00:00
Bug 1733107 - Add QuotaManager::RemoveOriginDirectory; r=dom-storage-reviewers,asuth
The removing of an origin directory became a bit more complex because when the app shutdown already started, origin directories shouldn't be fully removed from disk. They need to be only moved to a special directory. All this complexity should be covered by a dedicated QuotaManager method. Changes done in this patch: - added a new method QuotaManager::RemoveOriginDirectory - added a prefilled string for the special to-be-removed directory - adjusted ClearRequestBase::DeleteFiles to use the new QuotaManager::RemoveOriginDirectory method Differential Revision: https://phabricator.services.mozilla.com/D186780
This commit is contained in:
parent
72434a1513
commit
0806548c36
@ -48,6 +48,7 @@
|
||||
#include "mozStorageCID.h"
|
||||
#include "mozStorageHelper.h"
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/AppShutdown.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
@ -266,7 +267,8 @@ constexpr auto kStorageName = u"storage"_ns;
|
||||
#define PERMANENT_DIRECTORY_NAME u"permanent"
|
||||
#define TEMPORARY_DIRECTORY_NAME u"temporary"
|
||||
#define DEFAULT_DIRECTORY_NAME u"default"
|
||||
#define DEFAULT_PRIVATE_DIRECTORY_NAME u"private"
|
||||
#define PRIVATE_DIRECTORY_NAME u"private"
|
||||
#define TOBEREMOVED_DIRECTORY_NAME u"to-be-removed"
|
||||
|
||||
#define WEB_APPS_STORE_FILE_NAME u"webappsstore.sqlite"
|
||||
#define LS_ARCHIVE_FILE_NAME u"ls-archive.sqlite"
|
||||
@ -2095,9 +2097,13 @@ nsresult QuotaManager::Init() {
|
||||
do_Init(mDefaultStoragePath),
|
||||
GetPathForStorage(*baseDir, nsLiteralString(DEFAULT_DIRECTORY_NAME)));
|
||||
|
||||
QM_TRY_UNWRAP(do_Init(mPrivateStoragePath),
|
||||
GetPathForStorage(
|
||||
*baseDir, nsLiteralString(DEFAULT_PRIVATE_DIRECTORY_NAME)));
|
||||
QM_TRY_UNWRAP(
|
||||
do_Init(mPrivateStoragePath),
|
||||
GetPathForStorage(*baseDir, nsLiteralString(PRIVATE_DIRECTORY_NAME)));
|
||||
|
||||
QM_TRY_UNWRAP(
|
||||
do_Init(mToBeRemovedStoragePath),
|
||||
GetPathForStorage(*baseDir, nsLiteralString(TOBEREMOVED_DIRECTORY_NAME)));
|
||||
|
||||
QM_TRY_UNWRAP(do_Init(mIOThread),
|
||||
MOZ_TO_RESULT_INVOKE_TYPED(
|
||||
@ -3481,6 +3487,24 @@ Result<OriginMetadata, nsresult> QuotaManager::GetOriginMetadata(
|
||||
maybePersistenceType.value()};
|
||||
}
|
||||
|
||||
Result<Ok, nsresult> QuotaManager::RemoveOriginDirectory(nsIFile& aDirectory) {
|
||||
AssertIsOnIOThread();
|
||||
|
||||
if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownTeardown)) {
|
||||
QM_TRY_RETURN(MOZ_TO_RESULT(aDirectory.Remove(true)));
|
||||
}
|
||||
|
||||
QM_TRY_INSPECT(const auto& toBeRemovedStorageDir,
|
||||
QM_NewLocalFile(*mToBeRemovedStoragePath));
|
||||
|
||||
QM_TRY_INSPECT(const bool& created, EnsureDirectory(*toBeRemovedStorageDir));
|
||||
|
||||
(void)created;
|
||||
|
||||
QM_TRY_RETURN(MOZ_TO_RESULT(aDirectory.MoveTo(
|
||||
toBeRemovedStorageDir, NSID_TrimBracketsUTF16(nsID::GenerateUUID()))));
|
||||
}
|
||||
|
||||
template <typename OriginFunc>
|
||||
nsresult QuotaManager::InitializeRepository(PersistenceType aPersistenceType,
|
||||
OriginFunc&& aOriginFunc) {
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "FileUtils.h"
|
||||
#include "GroupInfo.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/AppShutdown.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
@ -1709,32 +1708,6 @@ void ClearStorageOp::CloseDirectory() {
|
||||
mDirectoryLock = nullptr;
|
||||
}
|
||||
|
||||
static Result<nsCOMPtr<nsIFile>, QMResult> OpenToBeRemovedDirectory(
|
||||
const nsAString& aStoragePath) {
|
||||
QM_TRY_INSPECT(const auto& dir,
|
||||
QM_TO_RESULT_TRANSFORM(QM_NewLocalFile(aStoragePath)));
|
||||
QM_TRY(QM_TO_RESULT(dir->Append(u"to-be-removed"_ns)));
|
||||
|
||||
nsresult rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0700);
|
||||
if (NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_ALREADY_EXISTS) {
|
||||
return dir;
|
||||
}
|
||||
return Err(QMResult(rv));
|
||||
}
|
||||
|
||||
static Result<Ok, QMResult> RemoveOrMoveToDir(nsIFile& aFile,
|
||||
nsIFile* aMoveTargetDir) {
|
||||
if (!aMoveTargetDir) {
|
||||
QM_TRY(QM_TO_RESULT(aFile.Remove(true)));
|
||||
return Ok();
|
||||
}
|
||||
|
||||
nsIDToCString uuid(nsID::GenerateUUID());
|
||||
NS_ConvertUTF8toUTF16 subDirName(uuid.get(), NSID_LENGTH - 1);
|
||||
QM_TRY(QM_TO_RESULT(aFile.MoveTo(aMoveTargetDir, subDirName)));
|
||||
return Ok();
|
||||
}
|
||||
|
||||
void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
|
||||
PersistenceType aPersistenceType,
|
||||
const OriginScope& aOriginScope,
|
||||
@ -1761,125 +1734,120 @@ void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
|
||||
|
||||
aQuotaManager.MaybeRecordQuotaManagerShutdownStep(
|
||||
"ClearRequestBase: Starting deleting files"_ns);
|
||||
nsCOMPtr<nsIFile> toBeRemovedDir;
|
||||
if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownTeardown)) {
|
||||
QM_WARNONLY_TRY_UNWRAP(
|
||||
auto result, OpenToBeRemovedDirectory(aQuotaManager.GetStoragePath()));
|
||||
toBeRemovedDir = result.valueOr(nullptr);
|
||||
}
|
||||
QM_TRY(
|
||||
CollectEachFile(
|
||||
*directory,
|
||||
[&aClientType, &originScope = aOriginScope, aPersistenceType,
|
||||
&aQuotaManager, &directoriesForRemovalRetry, &toBeRemovedDir](
|
||||
nsCOMPtr<nsIFile>&& file) -> mozilla::Result<Ok, nsresult> {
|
||||
QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*file));
|
||||
|
||||
QM_TRY_INSPECT(const auto& leafName,
|
||||
MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoString, file,
|
||||
GetLeafName));
|
||||
QM_TRY(CollectEachFile(
|
||||
*directory,
|
||||
[&aClientType, &originScope = aOriginScope, aPersistenceType,
|
||||
&aQuotaManager, &directoriesForRemovalRetry](
|
||||
nsCOMPtr<nsIFile>&& file) -> mozilla::Result<Ok, nsresult> {
|
||||
QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*file));
|
||||
|
||||
switch (dirEntryKind) {
|
||||
case nsIFileKind::ExistsAsDirectory: {
|
||||
QM_TRY_UNWRAP(
|
||||
auto maybeMetadata,
|
||||
QM_OR_ELSE_WARN_IF(
|
||||
// Expression
|
||||
aQuotaManager.GetOriginMetadata(file).map(
|
||||
[](auto metadata) -> Maybe<OriginMetadata> {
|
||||
return Some(std::move(metadata));
|
||||
}),
|
||||
// Predicate.
|
||||
IsSpecificError<NS_ERROR_MALFORMED_URI>,
|
||||
// Fallback.
|
||||
ErrToDefaultOk<Maybe<OriginMetadata>>));
|
||||
QM_TRY_INSPECT(const auto& leafName,
|
||||
MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
|
||||
nsAutoString, file, GetLeafName));
|
||||
|
||||
if (!maybeMetadata) {
|
||||
// Unknown directories during clearing are allowed. Just warn
|
||||
// if we find them.
|
||||
UNKNOWN_FILE_WARNING(leafName);
|
||||
break;
|
||||
}
|
||||
switch (dirEntryKind) {
|
||||
case nsIFileKind::ExistsAsDirectory: {
|
||||
QM_TRY_UNWRAP(
|
||||
auto maybeMetadata,
|
||||
QM_OR_ELSE_WARN_IF(
|
||||
// Expression
|
||||
aQuotaManager.GetOriginMetadata(file).map(
|
||||
[](auto metadata) -> Maybe<OriginMetadata> {
|
||||
return Some(std::move(metadata));
|
||||
}),
|
||||
// Predicate.
|
||||
IsSpecificError<NS_ERROR_MALFORMED_URI>,
|
||||
// Fallback.
|
||||
ErrToDefaultOk<Maybe<OriginMetadata>>));
|
||||
|
||||
auto metadata = maybeMetadata.extract();
|
||||
if (!maybeMetadata) {
|
||||
// Unknown directories during clearing are allowed. Just
|
||||
// warn if we find them.
|
||||
UNKNOWN_FILE_WARNING(leafName);
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(metadata.mPersistenceType == aPersistenceType);
|
||||
auto metadata = maybeMetadata.extract();
|
||||
|
||||
// Skip the origin directory if it doesn't match the pattern.
|
||||
if (!originScope.Matches(
|
||||
OriginScope::FromOrigin(metadata.mOrigin))) {
|
||||
break;
|
||||
}
|
||||
MOZ_ASSERT(metadata.mPersistenceType == aPersistenceType);
|
||||
|
||||
if (!aClientType.IsNull()) {
|
||||
nsAutoString clientDirectoryName;
|
||||
QM_TRY(
|
||||
OkIf(Client::TypeToText(aClientType.Value(),
|
||||
clientDirectoryName, fallible)),
|
||||
Err(NS_ERROR_FAILURE));
|
||||
// Skip the origin directory if it doesn't match the pattern.
|
||||
if (!originScope.Matches(
|
||||
OriginScope::FromOrigin(metadata.mOrigin))) {
|
||||
break;
|
||||
}
|
||||
|
||||
QM_TRY(MOZ_TO_RESULT(file->Append(clientDirectoryName)));
|
||||
if (!aClientType.IsNull()) {
|
||||
nsAutoString clientDirectoryName;
|
||||
QM_TRY(OkIf(Client::TypeToText(aClientType.Value(),
|
||||
clientDirectoryName,
|
||||
fallible)),
|
||||
Err(NS_ERROR_FAILURE));
|
||||
|
||||
QM_TRY_INSPECT(const bool& exists,
|
||||
MOZ_TO_RESULT_INVOKE_MEMBER(file, Exists));
|
||||
QM_TRY(MOZ_TO_RESULT(file->Append(clientDirectoryName)));
|
||||
|
||||
if (!exists) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
QM_TRY_INSPECT(const bool& exists,
|
||||
MOZ_TO_RESULT_INVOKE_MEMBER(file, Exists));
|
||||
|
||||
// We can't guarantee that this will always succeed on
|
||||
// Windows...
|
||||
QM_WARNONLY_TRY(
|
||||
RemoveOrMoveToDir(*file, toBeRemovedDir), [&](const auto&) {
|
||||
directoriesForRemovalRetry.AppendElement(std::move(file));
|
||||
});
|
||||
if (!exists) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const bool initialized =
|
||||
aPersistenceType == PERSISTENCE_TYPE_PERSISTENT
|
||||
? aQuotaManager.IsOriginInitialized(metadata.mOrigin)
|
||||
: aQuotaManager.IsTemporaryStorageInitialized();
|
||||
// We can't guarantee that this will always succeed on
|
||||
// Windows...
|
||||
QM_WARNONLY_TRY(aQuotaManager.RemoveOriginDirectory(*file),
|
||||
[&](const auto&) {
|
||||
directoriesForRemovalRetry.AppendElement(
|
||||
std::move(file));
|
||||
});
|
||||
|
||||
// If it hasn't been initialized, we don't need to update the
|
||||
// quota and notify the removing client.
|
||||
if (!initialized) {
|
||||
break;
|
||||
}
|
||||
const bool initialized =
|
||||
aPersistenceType == PERSISTENCE_TYPE_PERSISTENT
|
||||
? aQuotaManager.IsOriginInitialized(metadata.mOrigin)
|
||||
: aQuotaManager.IsTemporaryStorageInitialized();
|
||||
|
||||
if (aPersistenceType != PERSISTENCE_TYPE_PERSISTENT) {
|
||||
if (aClientType.IsNull()) {
|
||||
aQuotaManager.RemoveQuotaForOrigin(aPersistenceType,
|
||||
metadata);
|
||||
} else {
|
||||
aQuotaManager.ResetUsageForClient(
|
||||
ClientMetadata{metadata, aClientType.Value()});
|
||||
}
|
||||
}
|
||||
// If it hasn't been initialized, we don't need to update the
|
||||
// quota and notify the removing client.
|
||||
if (!initialized) {
|
||||
break;
|
||||
}
|
||||
|
||||
aQuotaManager.OriginClearCompleted(
|
||||
aPersistenceType, metadata.mOrigin, aClientType);
|
||||
if (aPersistenceType != PERSISTENCE_TYPE_PERSISTENT) {
|
||||
if (aClientType.IsNull()) {
|
||||
aQuotaManager.RemoveQuotaForOrigin(aPersistenceType,
|
||||
metadata);
|
||||
} else {
|
||||
aQuotaManager.ResetUsageForClient(
|
||||
ClientMetadata{metadata, aClientType.Value()});
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
aQuotaManager.OriginClearCompleted(
|
||||
aPersistenceType, metadata.mOrigin, aClientType);
|
||||
|
||||
case nsIFileKind::ExistsAsFile: {
|
||||
// Unknown files during clearing are allowed. Just warn if we
|
||||
// find them.
|
||||
if (!IsOSMetadata(leafName)) {
|
||||
UNKNOWN_FILE_WARNING(leafName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case nsIFileKind::ExistsAsFile: {
|
||||
// Unknown files during clearing are allowed. Just warn if we
|
||||
// find them.
|
||||
if (!IsOSMetadata(leafName)) {
|
||||
UNKNOWN_FILE_WARNING(leafName);
|
||||
}
|
||||
|
||||
case nsIFileKind::DoesNotExist:
|
||||
// Ignore files that got removed externally while iterating.
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return Ok{};
|
||||
}),
|
||||
QM_VOID);
|
||||
case nsIFileKind::DoesNotExist:
|
||||
// Ignore files that got removed externally while iterating.
|
||||
break;
|
||||
}
|
||||
|
||||
return Ok{};
|
||||
}),
|
||||
QM_VOID);
|
||||
|
||||
// Retry removing any directories that failed to be removed earlier now.
|
||||
//
|
||||
@ -1896,7 +1864,7 @@ void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
|
||||
for (auto&& file : std::exchange(directoriesForRemovalRetry,
|
||||
nsTArray<nsCOMPtr<nsIFile>>{})) {
|
||||
QM_WARNONLY_TRY(
|
||||
RemoveOrMoveToDir(*file, toBeRemovedDir),
|
||||
aQuotaManager.RemoveOriginDirectory(*file),
|
||||
([&directoriesForRemovalRetry, &file](const auto&) {
|
||||
directoriesForRemovalRetry.AppendElement(std::move(file));
|
||||
}));
|
||||
|
@ -262,6 +262,8 @@ class QuotaManager final : public BackgroundThreadObject {
|
||||
|
||||
Result<OriginMetadata, nsresult> GetOriginMetadata(nsIFile* aDirectory);
|
||||
|
||||
Result<Ok, nsresult> RemoveOriginDirectory(nsIFile& aDirectory);
|
||||
|
||||
RefPtr<UniversalDirectoryLockPromise> OpenStorageDirectory(
|
||||
const Nullable<PersistenceType>& aPersistenceType,
|
||||
const OriginScope& aOriginScope,
|
||||
@ -747,6 +749,7 @@ class QuotaManager final : public BackgroundThreadObject {
|
||||
LazyInitializedOnce<const nsString> mTemporaryStoragePath;
|
||||
LazyInitializedOnce<const nsString> mDefaultStoragePath;
|
||||
LazyInitializedOnce<const nsString> mPrivateStoragePath;
|
||||
LazyInitializedOnce<const nsString> mToBeRemovedStoragePath;
|
||||
|
||||
uint64_t mTemporaryStorageLimit;
|
||||
uint64_t mTemporaryStorageUsage;
|
||||
|
Loading…
x
Reference in New Issue
Block a user