Bug 1687321 - Use GetDirEntryKind instead of IsDirectory when iterating over directory entries in dom/cache. r=dom-workers-and-storage-reviewers,janv

Differential Revision: https://phabricator.services.mozilla.com/D103763
This commit is contained in:
Simon Giesecke 2021-02-08 13:15:50 +00:00
Родитель 3521cdde51
Коммит 26725b587f
3 изменённых файлов: 156 добавлений и 122 удалений

122
dom/cache/FileUtils.cpp поставляемый
Просмотреть файл

@ -30,6 +30,8 @@ using mozilla::dom::quota::Client;
using mozilla::dom::quota::CloneFileAndAppend;
using mozilla::dom::quota::FileInputStream;
using mozilla::dom::quota::FileOutputStream;
using mozilla::dom::quota::GetDirEntryKind;
using mozilla::dom::quota::nsIFileKind;
using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
using mozilla::dom::quota::QuotaManager;
using mozilla::dom::quota::QuotaObject;
@ -346,41 +348,52 @@ nsresult BodyDeleteOrphanedFiles(const QuotaInfo& aQuotaInfo, nsIFile& aBaseDir,
*dir,
[&aQuotaInfo, &aKnownBodyIdList](
const nsCOMPtr<nsIFile>& subdir) -> Result<Ok, nsresult> {
CACHE_TRY_INSPECT(const bool& isDir,
MOZ_TO_RESULT_INVOKE(subdir, IsDirectory));
CACHE_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*subdir));
// If a file got in here somehow, try to remove it and move on
CACHE_TRY(OkIf(isDir), Ok{}, ([&aQuotaInfo, &subdir](const auto&) {
DebugOnly<nsresult> result = RemoveNsIFile(
aQuotaInfo, *subdir, /* aTrackQuota */ false);
MOZ_ASSERT(NS_SUCCEEDED(result));
}));
switch (dirEntryKind) {
case nsIFileKind::ExistsAsDirectory: {
const auto removeOrphanedFiles =
[&aQuotaInfo, &aKnownBodyIdList](
nsIFile& bodyFile,
const nsACString& leafName) -> Result<bool, nsresult> {
// Finally, parse the uuid out of the name. If it fails to parse,
// then ignore the file.
auto cleanup = MakeScopeExit([&aQuotaInfo, &bodyFile] {
DebugOnly<nsresult> result =
RemoveNsIFile(aQuotaInfo, bodyFile);
MOZ_ASSERT(NS_SUCCEEDED(result));
});
const auto removeOrphanedFiles =
[&aQuotaInfo, &aKnownBodyIdList](
nsIFile& bodyFile,
const nsACString& leafName) -> Result<bool, nsresult> {
// Finally, parse the uuid out of the name. If it fails to parse,
// then ignore the file.
auto cleanup = MakeScopeExit([&aQuotaInfo, &bodyFile] {
DebugOnly<nsresult> result = RemoveNsIFile(aQuotaInfo, bodyFile);
MOZ_ASSERT(NS_SUCCEEDED(result));
});
nsID id;
CACHE_TRY(OkIf(id.Parse(leafName.BeginReading())), true);
nsID id;
CACHE_TRY(OkIf(id.Parse(leafName.BeginReading())), true);
if (!aKnownBodyIdList.Contains(id)) {
return true;
}
if (!aKnownBodyIdList.Contains(id)) {
return true;
cleanup.release();
return false;
};
CACHE_TRY(BodyTraverseFiles(aQuotaInfo, *subdir,
removeOrphanedFiles,
/* aCanRemoveFiles */ true,
/* aTrackQuota */ true));
break;
}
cleanup.release();
return false;
};
CACHE_TRY(BodyTraverseFiles(aQuotaInfo, *subdir, removeOrphanedFiles,
/* aCanRemoveFiles */ true,
/* aTrackQuota */ true));
case nsIFileKind::ExistsAsFile: {
// If a file got in here somehow, try to remove it and move on
DebugOnly<nsresult> result =
RemoveNsIFile(aQuotaInfo, *subdir, /* aTrackQuota */ false);
MOZ_ASSERT(NS_SUCCEEDED(result));
break;
}
case nsIFileKind::DoesNotExist:
// Ignore files that got removed externally while iterating.
break;
}
return Ok{};
}));
@ -440,32 +453,35 @@ bool MarkerFileExists(const QuotaInfo& aQuotaInfo) {
nsresult RemoveNsIFileRecursively(const QuotaInfo& aQuotaInfo, nsIFile& aFile,
const bool aTrackQuota) {
CACHE_TRY_INSPECT(const Maybe<bool>& maybeIsDirectory,
MOZ_TO_RESULT_INVOKE(aFile, IsDirectory)
.map(Some<bool>)
.orElse(MapNotFoundToDefault<Maybe<bool>>));
if (!maybeIsDirectory) {
return NS_OK;
CACHE_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(aFile));
switch (dirEntryKind) {
case nsIFileKind::ExistsAsDirectory:
// Unfortunately, we need to traverse all the entries and delete files one
// by
// one to update their usages to the QuotaManager.
CACHE_TRY(quota::CollectEachFile(
aFile,
[&aQuotaInfo, &aTrackQuota](
const nsCOMPtr<nsIFile>& file) -> Result<Ok, nsresult> {
CACHE_TRY(RemoveNsIFileRecursively(aQuotaInfo, *file, aTrackQuota));
return Ok{};
}));
// In the end, remove the folder
CACHE_TRY(aFile.Remove(/* recursive */ false));
break;
case nsIFileKind::ExistsAsFile:
return RemoveNsIFile(aQuotaInfo, aFile, aTrackQuota);
case nsIFileKind::DoesNotExist:
// Ignore files that got removed externally while iterating.
break;
}
if (!maybeIsDirectory.value()) {
return RemoveNsIFile(aQuotaInfo, aFile, aTrackQuota);
}
// Unfortunately, we need to traverse all the entries and delete files one by
// one to update their usages to the QuotaManager.
CACHE_TRY(quota::CollectEachFile(
aFile,
[&aQuotaInfo,
&aTrackQuota](const nsCOMPtr<nsIFile>& file) -> Result<Ok, nsresult> {
CACHE_TRY(RemoveNsIFileRecursively(aQuotaInfo, *file, aTrackQuota));
return Ok{};
}));
// In the end, remove the folder
CACHE_TRY(aFile.Remove(/* recursive */ false));
return NS_OK;
}

80
dom/cache/FileUtilsImpl.h поставляемый
Просмотреть файл

@ -38,46 +38,56 @@ nsresult BodyTraverseFiles(const QuotaInfo& aQuotaInfo, nsIFile& aBodyDir,
aBodyDir,
[&isEmpty, &aQuotaInfo, aTrackQuota, &aHandleFileFunc,
aCanRemoveFiles](const nsCOMPtr<nsIFile>& file) -> Result<Ok, nsresult> {
CACHE_TRY_INSPECT(const bool& isDir,
MOZ_TO_RESULT_INVOKE(file, IsDirectory));
CACHE_TRY_INSPECT(const auto& dirEntryKind,
quota::GetDirEntryKind(*file));
// If it's a directory somehow, try to remove it and move on
CACHE_TRY(OkIf(!isDir), Ok{}, ([&aQuotaInfo, &file](const auto&) {
DebugOnly<nsresult> result = RemoveNsIFileRecursively(
aQuotaInfo, *file, /* aTrackQuota */ false);
MOZ_ASSERT(NS_SUCCEEDED(result));
}));
nsAutoCString leafName;
CACHE_TRY(file->GetNativeLeafName(leafName));
// Delete all tmp files regardless of known bodies. These are all
// considered orphans.
if (StringEndsWith(leafName, ".tmp"_ns)) {
if (aCanRemoveFiles) {
DebugOnly<nsresult> result =
RemoveNsIFile(aQuotaInfo, *file, aTrackQuota);
switch (dirEntryKind) {
case quota::nsIFileKind::ExistsAsDirectory: {
// If it's a directory somehow, try to remove it and move on
DebugOnly<nsresult> result = RemoveNsIFileRecursively(
aQuotaInfo, *file, /* aTrackQuota */ false);
MOZ_ASSERT(NS_SUCCEEDED(result));
return Ok{};
break;
}
} else {
CACHE_TRY(OkIf(StringEndsWith(leafName, ".final"_ns)), Ok{},
([&aQuotaInfo, &file](const auto&) {
// Otherwise, it must be a .final file. If its not, then
// try to remove it and move on
DebugOnly<nsresult> result = RemoveNsIFile(
aQuotaInfo, *file, /* aTrackQuota */ false);
MOZ_ASSERT(NS_SUCCEEDED(result));
}));
}
CACHE_TRY_INSPECT(const bool& fileDeleted,
aHandleFileFunc(*file, leafName));
if (fileDeleted) {
return Ok{};
}
case quota::nsIFileKind::ExistsAsFile: {
nsAutoCString leafName;
CACHE_TRY(file->GetNativeLeafName(leafName));
isEmpty.EnsureFlipped();
// Delete all tmp files regardless of known bodies. These are all
// considered orphans.
if (StringEndsWith(leafName, ".tmp"_ns)) {
if (aCanRemoveFiles) {
DebugOnly<nsresult> result =
RemoveNsIFile(aQuotaInfo, *file, aTrackQuota);
MOZ_ASSERT(NS_SUCCEEDED(result));
return Ok{};
}
} else {
CACHE_TRY(OkIf(StringEndsWith(leafName, ".final"_ns)), Ok{},
([&aQuotaInfo, &file](const auto&) {
// Otherwise, it must be a .final file. If its not,
// then try to remove it and move on
DebugOnly<nsresult> result = RemoveNsIFile(
aQuotaInfo, *file, /* aTrackQuota */ false);
MOZ_ASSERT(NS_SUCCEEDED(result));
}));
}
CACHE_TRY_INSPECT(const bool& fileDeleted,
aHandleFileFunc(*file, leafName));
if (fileDeleted) {
return Ok{};
}
isEmpty.EnsureFlipped();
break;
}
case quota::nsIFileKind::DoesNotExist:
// Ignore files that got removed externally while iterating.
break;
}
return Ok{};
}));

76
dom/cache/QuotaClient.cpp поставляемый
Просмотреть файл

@ -415,44 +415,52 @@ Result<UsageInfo, nsresult> CacheQuotaClient::GetUsageForOriginInternal(
const auto& leafName,
MOZ_TO_RESULT_INVOKE_TYPED(nsAutoString, file, GetLeafName));
CACHE_TRY_INSPECT(const bool& isDir,
MOZ_TO_RESULT_INVOKE(file, IsDirectory));
CACHE_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*file));
if (isDir) {
if (leafName.EqualsLiteral("morgue")) {
CACHE_TRY_RETURN(GetBodyUsage(*file, aCanceled, aInitializing));
} else {
NS_WARNING("Unknown Cache directory found!");
}
switch (dirEntryKind) {
case nsIFileKind::ExistsAsDirectory:
if (leafName.EqualsLiteral("morgue")) {
CACHE_TRY_RETURN(
GetBodyUsage(*file, aCanceled, aInitializing));
} else {
NS_WARNING("Unknown Cache directory found!");
}
return UsageInfo{};
break;
case nsIFileKind::ExistsAsFile:
// Ignore transient sqlite files and marker files
if (leafName.EqualsLiteral("caches.sqlite-journal") ||
leafName.EqualsLiteral("caches.sqlite-shm") ||
leafName.Find("caches.sqlite-mj"_ns, false, 0, 0) == 0 ||
leafName.EqualsLiteral("context_open.marker")) {
break;
}
if (leafName.Equals(kCachesSQLiteFilename) ||
leafName.EqualsLiteral("caches.sqlite-wal")) {
CACHE_TRY_INSPECT(const int64_t& fileSize,
MOZ_TO_RESULT_INVOKE(file, GetFileSize));
MOZ_DIAGNOSTIC_ASSERT(fileSize >= 0);
return UsageInfo{DatabaseUsageType(Some(fileSize))};
}
// Ignore directory padding file
if (leafName.EqualsLiteral(PADDING_FILE_NAME) ||
leafName.EqualsLiteral(PADDING_TMP_FILE_NAME)) {
break;
}
NS_WARNING("Unknown Cache file found!");
break;
case nsIFileKind::DoesNotExist:
// Ignore files that got removed externally while iterating.
break;
}
// Ignore transient sqlite files and marker files
if (leafName.EqualsLiteral("caches.sqlite-journal") ||
leafName.EqualsLiteral("caches.sqlite-shm") ||
leafName.Find("caches.sqlite-mj"_ns, false, 0, 0) == 0 ||
leafName.EqualsLiteral("context_open.marker")) {
return UsageInfo{};
}
if (leafName.Equals(kCachesSQLiteFilename) ||
leafName.EqualsLiteral("caches.sqlite-wal")) {
CACHE_TRY_INSPECT(const int64_t& fileSize,
MOZ_TO_RESULT_INVOKE(file, GetFileSize));
MOZ_DIAGNOSTIC_ASSERT(fileSize >= 0);
return UsageInfo{DatabaseUsageType(Some(fileSize))};
}
// Ignore directory padding file
if (leafName.EqualsLiteral(PADDING_FILE_NAME) ||
leafName.EqualsLiteral(PADDING_TMP_FILE_NAME)) {
return UsageInfo{};
}
NS_WARNING("Unknown Cache file found!");
return UsageInfo{};
}));