Re-land "Make DeleteCache() recursive"

This adds a suppression on seemingly false tsan report for SHFileOperationW.

Original message:
This reuses base::FileEnumerator for the task on all platforms.

BUG=249362
[email protected]

Review URL: https://codereview.chromium.org/19599002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@212053 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/disk_cache/cache_util.cc b/net/disk_cache/cache_util.cc
index 2457553..7389960 100644
--- a/net/disk_cache/cache_util.cc
+++ b/net/disk_cache/cache_util.cc
@@ -5,6 +5,7 @@
 #include "net/disk_cache/cache_util.h"
 
 #include "base/file_util.h"
+#include "base/files/file_enumerator.h"
 #include "base/location.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -51,6 +52,26 @@
 
 namespace disk_cache {
 
+void DeleteCache(const base::FilePath& path, bool remove_folder) {
+  if (remove_folder) {
+    if (!base::DeleteFile(path, /* recursive */ true))
+      LOG(WARNING) << "Unable to delete cache folder.";
+    return;
+  }
+
+  base::FileEnumerator iter(
+      path,
+      /* recursive */ false,
+      base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
+  for (base::FilePath file = iter.Next(); !file.value().empty();
+       file = iter.Next()) {
+    if (!base::DeleteFile(file, /* recursive */ true)) {
+      LOG(WARNING) << "Unable to delete cache.";
+      return;
+    }
+  }
+}
+
 // In order to process a potentially large number of files, we'll rename the
 // cache directory to old_ + original_name + number, (located on the same parent
 // directory), and use a worker thread to delete all the files on all the stale
diff --git a/net/disk_cache/cache_util_posix.cc b/net/disk_cache/cache_util_posix.cc
index 2b13d9e5..b33c560a 100644
--- a/net/disk_cache/cache_util_posix.cc
+++ b/net/disk_cache/cache_util_posix.cc
@@ -39,26 +39,6 @@
 #endif
 }
 
-void DeleteCache(const base::FilePath& path, bool remove_folder) {
-  base::FileEnumerator iter(path,
-                            /* recursive */ false,
-                            base::FileEnumerator::FILES);
-  for (base::FilePath file = iter.Next(); !file.value().empty();
-       file = iter.Next()) {
-    if (!base::DeleteFile(file, /* recursive */ false)) {
-      LOG(WARNING) << "Unable to delete cache.";
-      return;
-    }
-  }
-
-  if (remove_folder) {
-    if (!base::DeleteFile(path, /* recursive */ false)) {
-      LOG(WARNING) << "Unable to delete cache folder.";
-      return;
-    }
-  }
-}
-
 bool DeleteCacheFile(const base::FilePath& name) {
   return base::DeleteFile(name, false);
 }
diff --git a/net/disk_cache/cache_util_unittest.cc b/net/disk_cache/cache_util_unittest.cc
index 51d04432..d2e7605 100644
--- a/net/disk_cache/cache_util_unittest.cc
+++ b/net/disk_cache/cache_util_unittest.cc
@@ -19,6 +19,7 @@
     file1_ = base::FilePath(cache_dir_.Append(FILE_PATH_LITERAL("file01")));
     file2_ = base::FilePath(cache_dir_.Append(FILE_PATH_LITERAL(".file02")));
     dir1_ = base::FilePath(cache_dir_.Append(FILE_PATH_LITERAL("dir01")));
+    file3_ = base::FilePath(dir1_.Append(FILE_PATH_LITERAL("file03")));
     ASSERT_TRUE(file_util::CreateDirectory(cache_dir_));
     FILE *fp = file_util::OpenFile(file1_, "w");
     ASSERT_TRUE(fp != NULL);
@@ -27,6 +28,9 @@
     ASSERT_TRUE(fp != NULL);
     file_util::CloseFile(fp);
     ASSERT_TRUE(file_util::CreateDirectory(dir1_));
+    fp = file_util::OpenFile(file3_, "w");
+    ASSERT_TRUE(fp != NULL);
+    file_util::CloseFile(fp);
     dest_dir_ = tmp_dir_.path().Append(FILE_PATH_LITERAL("old_Cache_001"));
     dest_file1_ = base::FilePath(dest_dir_.Append(FILE_PATH_LITERAL("file01")));
     dest_file2_ =
@@ -40,6 +44,7 @@
   base::FilePath file1_;
   base::FilePath file2_;
   base::FilePath dir1_;
+  base::FilePath file3_;
   base::FilePath dest_dir_;
   base::FilePath dest_file1_;
   base::FilePath dest_file2_;
@@ -63,29 +68,29 @@
 }
 
 TEST_F(CacheUtilTest, DeleteCache) {
-  // DeleteCache won't delete subdirs, so let's not start with this
-  // one around.
-  base::DeleteFile(dir1_, false);
   disk_cache::DeleteCache(cache_dir_, false);
   EXPECT_TRUE(base::PathExists(cache_dir_)); // cache dir stays
+  EXPECT_FALSE(base::PathExists(dir1_));
   EXPECT_FALSE(base::PathExists(file1_));
   EXPECT_FALSE(base::PathExists(file2_));
+  EXPECT_FALSE(base::PathExists(file3_));
 }
 
 TEST_F(CacheUtilTest, DeleteCacheAndDir) {
-  // DeleteCache won't delete subdirs, so let's not start with this
-  // one around.
-  base::DeleteFile(dir1_, false);
   disk_cache::DeleteCache(cache_dir_, true);
   EXPECT_FALSE(base::PathExists(cache_dir_)); // cache dir is gone
+  EXPECT_FALSE(base::PathExists(dir1_));
   EXPECT_FALSE(base::PathExists(file1_));
   EXPECT_FALSE(base::PathExists(file2_));
+  EXPECT_FALSE(base::PathExists(file3_));
 }
 
 TEST_F(CacheUtilTest, DeleteCacheFile) {
   EXPECT_TRUE(disk_cache::DeleteCacheFile(file1_));
   EXPECT_FALSE(base::PathExists(file1_));
   EXPECT_TRUE(base::PathExists(cache_dir_)); // cache dir stays
+  EXPECT_TRUE(base::PathExists(dir1_));
+  EXPECT_TRUE(base::PathExists(file3_));
 }
 
 }  // namespace disk_cache
diff --git a/net/disk_cache/cache_util_win.cc b/net/disk_cache/cache_util_win.cc
index 8c54b91..33375116 100644
--- a/net/disk_cache/cache_util_win.cc
+++ b/net/disk_cache/cache_util_win.cc
@@ -11,29 +11,6 @@
 #include "base/message_loop.h"
 #include "base/win/scoped_handle.h"
 
-namespace {
-
-// Deletes all the files on path that match search_name pattern.
-void DeleteFiles(const base::FilePath& path, const wchar_t* search_name) {
-  base::FilePath name(path.Append(search_name));
-
-  WIN32_FIND_DATA data;
-  HANDLE handle = FindFirstFile(name.value().c_str(), &data);
-  if (handle == INVALID_HANDLE_VALUE)
-    return;
-
-  do {
-    if (data.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY ||
-        data.dwFileAttributes == FILE_ATTRIBUTE_REPARSE_POINT)
-      continue;
-    DeleteFile(path.Append(data.cFileName).value().c_str());
-  } while (FindNextFile(handle, &data));
-
-  FindClose(handle);
-}
-
-}  // namespace
-
 namespace disk_cache {
 
 bool MoveCache(const base::FilePath& from_path, const base::FilePath& to_path) {
@@ -46,12 +23,6 @@
   return true;
 }
 
-void DeleteCache(const base::FilePath& path, bool remove_folder) {
-  DeleteFiles(path, L"*");
-  if (remove_folder)
-    RemoveDirectory(path.value().c_str());
-}
-
 bool DeleteCacheFile(const base::FilePath& name) {
   // We do a simple delete, without ever falling back to SHFileOperation, as the
   // version from base does.
diff --git a/tools/valgrind/tsan/ignores_win32.txt b/tools/valgrind/tsan/ignores_win32.txt
index e1eb55f..9be6e40 100644
--- a/tools/valgrind/tsan/ignores_win32.txt
+++ b/tools/valgrind/tsan/ignores_win32.txt
@@ -46,3 +46,8 @@
 
 # ffmpegsumo.dll appears to read a few bytes beyond the end of the buffer.
 fun:_ff_prefetch_mmxext
+
+# Shows up as a race in SHELL32.dll when deleting a directory while opening an
+# unrelated file in another thread. Revealed by DiskCacheBackendTest.DeleteOld.
+# See: https://code.google.com/p/data-race-test/issues/detail?id=114
+fun_r:SHFileOperationW