Index: content/browser/storage_partition_impl_map.cc |
diff --git a/content/browser/storage_partition_impl_map.cc b/content/browser/storage_partition_impl_map.cc |
index eb7ae78007f5b83bd6851f1bb68e9e7a658be78c..10085b49b3e71dcb9e0df0c39911e8121f115f14 100644 |
--- a/content/browser/storage_partition_impl_map.cc |
+++ b/content/browser/storage_partition_impl_map.cc |
@@ -7,9 +7,11 @@ |
#include "base/bind.h" |
#include "base/callback.h" |
#include "base/file_path.h" |
+#include "base/file_util.h" |
#include "base/stl_util.h" |
#include "base/string_util.h" |
#include "base/string_number_conversions.h" |
+#include "base/threading/worker_pool.h" |
#include "content/browser/appcache/chrome_appcache_service.h" |
#include "content/browser/fileapi/browser_file_system_helper.h" |
#include "content/browser/fileapi/chrome_blob_storage_context.h" |
@@ -22,6 +24,7 @@ |
#include "content/browser/tcmalloc_internals_request_job.h" |
#include "content/public/browser/browser_context.h" |
#include "content/public/browser/browser_thread.h" |
+#include "content/public/browser/content_browser_client.h" |
#include "content/public/browser/storage_partition.h" |
#include "content/public/common/content_constants.h" |
#include "content/public/common/url_constants.h" |
@@ -238,6 +241,85 @@ const FilePath::CharType kDefaultPartitionDirname[] = |
// partition domain. |
const int kPartitionNameHashBytes = 6; |
+// Needed for selecting all files in ObliterateOneDirectory() below. |
+#if defined(OS_POSIX) |
nasko
2012/11/15 17:48:10
Why not put these right before the function that u
awong
2012/11/16 00:36:04
Was keeping all constants grouped...
|
+const int kAllFileTypes = file_util::FileEnumerator::FILES | |
+ file_util::FileEnumerator::DIRECTORIES | |
+ file_util::FileEnumerator::SHOW_SYM_LINKS; |
+#else |
+const int kAllFileTypes = file_util::FileEnumerator::FILES | |
+ file_util::FileEnumerator::DIRECTORIES; |
+#endif |
+ |
+FilePath GetStoragePartitionDomainPath( |
+ const std::string& partition_domain) { |
+ CHECK(IsStringUTF8(partition_domain)); |
+ |
+ return FilePath(kStoragePartitionDirname).Append(kExtensionsDirname) |
+ .Append(FilePath::FromUTF8Unsafe(partition_domain)); |
+} |
+ |
+// Helper function for doing a depth-first deletion of the data on disk. |
+// Examines paths directly in |current_dir| (no recursion) and tries to |
+// delete from disk anything that is in, or isn't a parent of something in |
+// |paths_to_keep|. Paths that need further expansion are added to |
+// |paths_to_consider|. |
+void ObliterateOneDirectory(const FilePath& current_dir, |
Charlie Reis
2012/11/15 18:28:21
Why so violent? :) Obliterate seems like an unus
awong
2012/11/16 00:36:04
I was avoiding "Delete" because there's so many De
|
+ const std::vector<FilePath>& paths_to_keep, |
+ std::vector<FilePath>* paths_to_consider) { |
+ file_util::FileEnumerator enumerator(current_dir, false, kAllFileTypes); |
+ for (FilePath to_delete = enumerator.Next(); !to_delete.empty(); |
+ to_delete = enumerator.Next()) { |
+ for (std::vector<FilePath>::const_iterator to_keep = paths_to_keep.begin(); |
+ to_keep != paths_to_keep.end(); |
+ ++to_keep) { |
+ if (to_delete == *to_keep) { |
+ // Do nothing because this path shouldn't be deleted. |
+ } else if (to_delete.IsParent(*to_keep)) { |
+ // |to_delete| contains a path to keep. Add to stack for further |
+ // processing. |
+ paths_to_consider->push_back(*to_keep); |
+ } else { |
+ // |to_delete| isn't protected. Just delete it. |
+ file_util::Delete(to_delete, true); |
+ } |
+ } |
+ } |
+} |
+ |
+// Synchronously attempts to delete |root|, preserving only entries in |
+// |paths_to_keep|. If there are no entries in |paths_to_keep| on disk, then it |
+// completely removes |root|. All paths must be absolute paths. |
+void BlockingObliteratePath(const FilePath& root, |
+ const std::vector<FilePath>& paths_to_keep) { |
+ // Reduce |active_paths| set to those under the root and actually on disk. |
nasko
2012/11/15 17:48:10
What is |active_paths|?
awong
2012/11/16 00:36:04
Old name. Fixed.
|
+ std::vector<FilePath> valid_paths_to_keep; |
+ for (std::vector<FilePath>::const_iterator it = paths_to_keep.begin(); |
+ it != paths_to_keep.end(); |
+ ++it) { |
+ if (root.IsParent(*it) && file_util::PathExists(*it)) { |
nasko
2012/11/15 17:48:10
nit: no braces needed.
awong
2012/11/16 00:36:04
Done.
|
+ valid_paths_to_keep.push_back(*it); |
+ } |
+ } |
+ |
+ // If none of the |paths_to_keep| are valid anymore then we just whack the |
+ // root and be done with it. |
+ if (valid_paths_to_keep.empty()) { |
+ file_util::Delete(root, true); |
+ return; |
+ } |
+ |
+ // Otherwise, start at the root and delete everything that is not in |
+ // |valid_paths_to_keep|. |
+ std::vector<FilePath> paths_to_consider; |
+ paths_to_consider.push_back(root); |
+ while(!paths_to_consider.empty()) { |
+ FilePath path = paths_to_consider.back(); |
+ paths_to_consider.pop_back(); |
+ ObliterateOneDirectory(path, valid_paths_to_keep, &paths_to_consider); |
+ } |
+} |
+ |
} // namespace |
// static |
@@ -247,11 +329,12 @@ FilePath StoragePartitionImplMap::GetStoragePartitionPath( |
if (partition_domain.empty()) |
return FilePath(); |
- CHECK(IsStringUTF8(partition_domain)); |
- |
- FilePath path = FilePath(kStoragePartitionDirname).Append(kExtensionsDirname) |
- .Append(FilePath::FromUTF8Unsafe(partition_domain)); |
+ FilePath path = GetStoragePartitionDomainPath(partition_domain); |
+ // TODO(ajwong): Mangle in-memory into this somehow, either by putting |
+ // it into the partition_name, or by manually adding another path component |
+ // here. Otherwise, it's possible to have an in-memory StoragePartition and |
+ // a persistent one that return the same FilePath for GetPath(). |
nasko
2012/11/15 17:48:10
Adding a path component might not work with the qu
awong
2012/11/16 00:36:04
The more I think about this, the more I think we s
|
if (!partition_name.empty()) { |
// For analysis of why we can ignore collisions, see the comment above |
// kPartitionNameHashBytes. |
@@ -264,7 +347,6 @@ FilePath StoragePartitionImplMap::GetStoragePartitionPath( |
return path.Append(kDefaultPartitionDirname); |
} |
- |
StoragePartitionImplMap::StoragePartitionImplMap( |
BrowserContext* browser_context) |
: browser_context_(browser_context), |
@@ -322,6 +404,52 @@ StoragePartitionImpl* StoragePartitionImplMap::Get( |
return partition; |
} |
+void StoragePartitionImplMap::AsyncObliterate(const GURL& site) { |
+ // This method should avoid creating any StoragePartition (which would |
+ // create more open file handles) so that it can delete as much of the |
+ // data off disk as possible. |
+ std::string partition_domain; |
+ std::string partition_name; |
+ bool in_memory = false; |
+ GetContentClient()->browser()->GetStoragePartitionConfigForSite( |
+ browser_context_, site, &partition_domain, |
+ &partition_name, &in_memory); |
+ |
+ // The default partition is the whole profile. We can't obliterate that and |
+ // should never even try. |
+ CHECK(!partition_domain.empty()); |
+ |
+ // Find the active partitions for the domain. Because these cannot be removed |
+ // from disk, start deletions in all of them. |
+ std::vector<StoragePartitionImpl*> active_partitions; |
+ std::vector<FilePath> paths_to_keep; |
+ for (PartitionMap::const_iterator it = partitions_.begin(); |
+ it != partitions_.end(); |
+ ++it) { |
+ const StoragePartitionConfig& config = it->first; |
+ if (config.partition_domain == partition_domain) { |
+ it->second->AsyncClearAllData(); |
+ if (!config.in_memory) { |
nasko
2012/11/15 17:48:10
nit: no braces needed.
awong
2012/11/16 00:36:04
Done.
|
+ paths_to_keep.push_back(it->second->GetPath()); |
+ } |
+ } |
+ } |
+ |
+ // Start a best-effort delete of the on-disk storage excluding paths that are |
+ // known to still be in use. This is to delete any previously created |
+ // StoragePartition state that just happens to not been used during this run |
+ // of the browser. |
+ // |
+ // TODO(ajwong): Schedule a final cleanup of the whole directory on the next |
+ // browser start. |
+ FilePath domain_root = browser_context_->GetPath().Append( |
+ GetStoragePartitionDomainPath(partition_domain)); |
+ base::WorkerPool::PostTask( |
+ FROM_HERE, |
+ base::Bind(&BlockingObliteratePath, domain_root, paths_to_keep), |
+ true); |
+} |
+ |
void StoragePartitionImplMap::ForEach( |
const BrowserContext::StoragePartitionCallback& callback) { |
for (PartitionMap::const_iterator it = partitions_.begin(); |
@@ -333,6 +461,7 @@ void StoragePartitionImplMap::ForEach( |
void StoragePartitionImplMap::PostCreateInitialization( |
StoragePartitionImpl* partition) { |
+ // TODO(ajwong): I think we lost the in-memory portion here. |
// Check first to avoid memory leak in unittests. |
if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { |
BrowserThread::PostTask( |