diff --git a/dom/cache/FileUtils.cpp b/dom/cache/FileUtils.cpp index 0e75962d85c5..6d37b03d53cb 100644 --- a/dom/cache/FileUtils.cpp +++ b/dom/cache/FileUtils.cpp @@ -358,72 +358,41 @@ nsresult BodyMaybeUpdatePaddingSize(const QuotaInfo& aQuotaInfo, nsresult BodyDeleteFiles(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir, const nsTArray& aIdList) { nsresult rv = NS_OK; - - for (uint32_t i = 0; i < aIdList.Length(); ++i) { - nsCOMPtr tmpFile; - rv = BodyIdToFile(aBaseDir, aIdList[i], BODY_FILE_TMP, - getter_AddRefs(tmpFile)); + for (const auto id : aIdList) { + nsCOMPtr bodyDir; + rv = BodyGetCacheDir(aBaseDir, id, getter_AddRefs(bodyDir)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - rv = RemoveNsIFile(aQuotaInfo, tmpFile); - // Only treat file deletion as a hard failure in DEBUG builds. Users - // can unfortunately hit this on windows if anti-virus is scanning files, - // etc. - MOZ_ASSERT(NS_SUCCEEDED(rv)); + const auto removeFileForId = [&aQuotaInfo, &id](nsIFile* bodyFile, + const nsACString& leafName, + bool& fileDeleted) { + MOZ_DIAGNOSTIC_ASSERT(bodyFile); - nsCOMPtr finalFile; - rv = BodyIdToFile(aBaseDir, aIdList[i], BODY_FILE_FINAL, - getter_AddRefs(finalFile)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - nsCOMPtr bodyDirectory; - rv = finalFile->GetParent(getter_AddRefs(bodyDirectory)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - rv = RemoveNsIFile(aQuotaInfo, finalFile); - // Again, only treat removal as hard failure in debug build. - MOZ_ASSERT(NS_SUCCEEDED(rv)); - - // Checking if the directory is empty or not. If it's, then remove the - // directory as well. - nsCOMPtr entries; - rv = bodyDirectory->GetDirectoryEntries(getter_AddRefs(entries)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - bool isEmpty = true; - nsCOMPtr file; - while (NS_SUCCEEDED(rv = entries->GetNextFile(getter_AddRefs(file))) && - file) { - nsAutoCString leafName; - rv = file->GetNativeLeafName(leafName); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; + nsID fileId; + if (NS_WARN_IF(!fileId.Parse(leafName.BeginReading()))) { + DebugOnly result = + RemoveNsIFile(aQuotaInfo, bodyFile, /* aTrackQuota */ false); + MOZ_ASSERT(NS_SUCCEEDED(result)); + fileDeleted = true; + return NS_OK; } - if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".tmp")) || - StringEndsWith(leafName, NS_LITERAL_CSTRING(".final"))) { - isEmpty = false; - break; + if (id.Equals(fileId)) { + DebugOnly result = RemoveNsIFile(aQuotaInfo, bodyFile); + MOZ_ASSERT(NS_SUCCEEDED(result)); + fileDeleted = true; + return NS_OK; } - } + + fileDeleted = false; + return NS_OK; + }; + rv = BodyTraverseFiles(aQuotaInfo, bodyDir, removeFileForId); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - - if (isEmpty) { - DebugOnly result = - RemoveNsIFileRecursively(aQuotaInfo, bodyDirectory, - /* aTrackQuota */ false); - MOZ_ASSERT(NS_SUCCEEDED(result)); - } } return NS_OK; @@ -566,83 +535,34 @@ nsresult BodyDeleteOrphanedFiles(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir, continue; } - nsCOMPtr subEntries; - rv = subdir->GetDirectoryEntries(getter_AddRefs(subEntries)); + const auto removeOrphanedFiles = + [&aQuotaInfo, &aKnownBodyIdList]( + nsIFile* bodyFile, const nsACString& leafName, bool& fileDeleted) { + MOZ_DIAGNOSTIC_ASSERT(bodyFile); + // Finally, parse the uuid out of the name. If its fails to parse, + // the ignore the file. + nsID id; + if (NS_WARN_IF(!id.Parse(leafName.BeginReading()))) { + DebugOnly result = RemoveNsIFile(aQuotaInfo, bodyFile); + MOZ_ASSERT(NS_SUCCEEDED(result)); + fileDeleted = true; + return NS_OK; + } + + if (!aKnownBodyIdList.Contains(id)) { + DebugOnly result = RemoveNsIFile(aQuotaInfo, bodyFile); + MOZ_ASSERT(NS_SUCCEEDED(result)); + fileDeleted = true; + return NS_OK; + } + + fileDeleted = false; + return NS_OK; + }; + rv = BodyTraverseFiles(aQuotaInfo, subdir, removeOrphanedFiles); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - - bool isEmpty = true; - // Now iterate over all the files in the subdir - nsCOMPtr file; - while (NS_SUCCEEDED(rv = subEntries->GetNextFile(getter_AddRefs(file))) && - file) { - bool isDirectory = false; - rv = file->IsDirectory(&isDirectory); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - // If it's a directory somehow, try to remove it and move on - if (isDirectory) { - DebugOnly result = - RemoveNsIFileRecursively(aQuotaInfo, file, /* aTrackQuota */ false); - MOZ_ASSERT(NS_SUCCEEDED(result)); - continue; - } - - nsAutoCString leafName; - rv = file->GetNativeLeafName(leafName); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - // Delete all tmp files regardless of known bodies. These are all - // considered orphans. - if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".tmp"))) { - DebugOnly result = RemoveNsIFile(aQuotaInfo, file); - MOZ_ASSERT(NS_SUCCEEDED(result)); - continue; - } - - nsCString suffix(NS_LITERAL_CSTRING(".final")); - - // Otherwise, it must be a .final file. If its not, then try to remove it - // and move on - if (NS_WARN_IF(!StringEndsWith(leafName, suffix) || - leafName.Length() != NSID_LENGTH - 1 + suffix.Length())) { - DebugOnly result = RemoveNsIFile(aQuotaInfo, file); - MOZ_ASSERT(NS_SUCCEEDED(result)); - continue; - } - - // Finally, parse the uuid out of the name. If its fails to parse, - // the ignore the file. - nsID id; - if (NS_WARN_IF(!id.Parse(leafName.BeginReading()))) { - DebugOnly result = - RemoveNsIFile(aQuotaInfo, file, /* aTrackQuota */ false); - MOZ_ASSERT(NS_SUCCEEDED(result)); - continue; - } - - if (!aKnownBodyIdList.Contains(id)) { - DebugOnly result = RemoveNsIFile(aQuotaInfo, file); - MOZ_ASSERT(NS_SUCCEEDED(result)); - continue; - } - - isEmpty = false; - } - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - if (isEmpty) { - DebugOnly result = - RemoveNsIFileRecursively(aQuotaInfo, subdir, /* aTrackQuota */ false); - MOZ_ASSERT(NS_SUCCEEDED(result)); - } } if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -651,6 +571,101 @@ nsresult BodyDeleteOrphanedFiles(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir, return rv; } +template +nsresult BodyTraverseFiles(const QuotaInfo& aQuotaInfo, nsIFile* aBodyDir, + const Func& aHandleFileFunc, + const bool aTrackQuota) { + MOZ_DIAGNOSTIC_ASSERT(aBodyDir); + + nsresult rv; +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + nsCOMPtr parentFile; + rv = aBodyDir->GetParent(getter_AddRefs(parentFile)); + MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); + MOZ_DIAGNOSTIC_ASSERT(parentFile); + + nsAutoCString nativeLeafName; + rv = parentFile->GetNativeLeafName(nativeLeafName); + MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); + + MOZ_DIAGNOSTIC_ASSERT( + StringEndsWith(nativeLeafName, NS_LITERAL_CSTRING("morgue"))); +#endif + + nsCOMPtr entries; + rv = aBodyDir->GetDirectoryEntries(getter_AddRefs(entries)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + bool isEmpty = true; + nsCOMPtr file; + while (NS_SUCCEEDED(rv = entries->GetNextFile(getter_AddRefs(file))) && + file) { + bool isDir = false; + rv = file->IsDirectory(&isDir); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // If it's a directory somehow, try to remove it and move on + if (NS_WARN_IF(isDir)) { + DebugOnly result = + RemoveNsIFileRecursively(aQuotaInfo, file, /* aTrackQuota */ false); + MOZ_ASSERT(NS_SUCCEEDED(result)); + continue; + } + + nsAutoCString leafName; + rv = file->GetNativeLeafName(leafName); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Delete all tmp files regardless of known bodies. These are all + // considered orphans. + if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".tmp"))) { + DebugOnly result = RemoveNsIFile(aQuotaInfo, file, aTrackQuota); + MOZ_ASSERT(NS_SUCCEEDED(result)); + continue; + } + + nsCString suffix(NS_LITERAL_CSTRING(".final")); + + // Otherwise, it must be a .final file. If its not, then try to remove it + // and move on + if (NS_WARN_IF(!StringEndsWith(leafName, suffix) || + leafName.Length() != NSID_LENGTH - 1 + suffix.Length())) { + DebugOnly result = + RemoveNsIFile(aQuotaInfo, file, /* aTrackQuota */ false); + MOZ_ASSERT(NS_SUCCEEDED(result)); + continue; + } + + bool fileDeleted; + rv = aHandleFileFunc(file, leafName, fileDeleted); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + if (fileDeleted) { + continue; + } + + isEmpty = false; + } + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (isEmpty) { + DebugOnly result = + RemoveNsIFileRecursively(aQuotaInfo, aBodyDir, /* aTrackQuota */ false); + MOZ_ASSERT(NS_SUCCEEDED(result)); + } + + return rv; +} + namespace { nsresult GetMarkerFileHandle(const QuotaInfo& aQuotaInfo, nsIFile** aFileOut) { diff --git a/dom/cache/FileUtils.h b/dom/cache/FileUtils.h index 3dfdbe2b02a0..bf15b6f1f5e9 100644 --- a/dom/cache/FileUtils.h +++ b/dom/cache/FileUtils.h @@ -58,6 +58,11 @@ nsresult BodyDeleteFiles(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir, nsresult BodyDeleteOrphanedFiles(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir, nsTArray& aKnownBodyIdList); +template +nsresult BodyTraverseFiles(const QuotaInfo& aQuotaInfo, nsIFile* aBodyDir, + const Func& aHandleFileFunc, + const bool aTrackQuota = true); + nsresult CreateMarkerFile(const QuotaInfo& aQuotaInfo); nsresult DeleteMarkerFile(const QuotaInfo& aQuotaInfo); diff --git a/dom/cache/QuotaClient.cpp b/dom/cache/QuotaClient.cpp index 88f4dca8c667..917fc1912f16 100644 --- a/dom/cache/QuotaClient.cpp +++ b/dom/cache/QuotaClient.cpp @@ -68,56 +68,30 @@ static nsresult GetBodyUsage(nsIFile* aMorgueDir, const Atomic& aCanceled, continue; } - nsCOMPtr subEntries; - rv = bodyDir->GetDirectoryEntries(getter_AddRefs(subEntries)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - bool isEmpty = true; - nsCOMPtr bodyFile; - while ( - NS_SUCCEEDED(rv = subEntries->GetNextFile(getter_AddRefs(bodyFile))) && - bodyFile && !aCanceled) { - bool isDirectory; - rv = bodyFile->IsDirectory(&isDirectory); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - if (isDirectory) { - QuotaInfo dummy; - mozilla::DebugOnly result = - RemoveNsIFileRecursively(dummy, bodyFile, /* aTrackQuota */ false); - // Try to remove the unexpected files, and keep moving on even if it - // fails because it might be created by virus or the operation system - MOZ_ASSERT(NS_SUCCEEDED(result)); - continue; - } - - isEmpty = false; + const QuotaInfo dummy; + const auto getUsage = [&aUsageInfo](nsIFile* bodyFile, + const nsACString& leafName, + bool& fileDeleted) { + MOZ_DIAGNOSTIC_ASSERT(bodyFile); + Unused << leafName; int64_t fileSize; - rv = bodyFile->GetFileSize(&fileSize); + nsresult rv = bodyFile->GetFileSize(&fileSize); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } MOZ_DIAGNOSTIC_ASSERT(fileSize >= 0); - aUsageInfo->AppendToFileUsage(Some(fileSize)); - } + + fileDeleted = false; + + return NS_OK; + }; + rv = mozilla::dom::cache::BodyTraverseFiles(dummy, bodyDir, getUsage, + /* aTrackQuota */ false); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - - if (isEmpty) { - QuotaInfo dummy; - mozilla::DebugOnly result = - RemoveNsIFileRecursively(dummy, bodyDir, /* aTrackQuota */ false); - // Try to remove the unexpected files, and keep moving on even if it - // fails because it might be created by virus or the operation system - MOZ_ASSERT(NS_SUCCEEDED(result)); - } } if (NS_WARN_IF(NS_FAILED(rv))) { return rv;