Index: webkit/database/database_tracker.cc |
diff --git a/webkit/database/database_tracker.cc b/webkit/database/database_tracker.cc |
index 7497c3814c7262279eeac8a242b42b1c921505d1..d01acda0c37780b2ed98e87cdd4b3400630fecc0 100644 |
--- a/webkit/database/database_tracker.cc |
+++ b/webkit/database/database_tracker.cc |
@@ -15,6 +15,7 @@ |
#include "base/basictypes.h" |
#include "base/file_util.h" |
#include "base/message_loop_proxy.h" |
+#include "base/platform_file.h" |
#include "base/string_number_conversions.h" |
#include "base/utf_string_conversions.h" |
#include "net/base/net_errors.h" |
@@ -47,7 +48,11 @@ const FilePath::CharType kTrackerDatabaseFileName[] = |
FILE_PATH_LITERAL("Databases.db"); |
static const int kCurrentVersion = 2; |
static const int kCompatibleVersion = 1; |
-static const char* kExtensionOriginIdentifierPrefix = "chrome-extension_"; |
+ |
+const FilePath::CharType kTemporaryDirectoryPrefix[] = |
+ FILE_PATH_LITERAL("DeleteMe"); |
+const FilePath::CharType kTemporaryDirectoryPattern[] = |
+ FILE_PATH_LITERAL("DeleteMe*"); |
OriginInfo::OriginInfo() |
: total_size_(0) {} |
@@ -87,11 +92,13 @@ OriginInfo::OriginInfo(const string16& origin, int64 total_size) |
DatabaseTracker::DatabaseTracker( |
const FilePath& profile_path, |
bool is_incognito, |
+ bool clear_local_state_on_exit, |
quota::SpecialStoragePolicy* special_storage_policy, |
quota::QuotaManagerProxy* quota_manager_proxy, |
base::MessageLoopProxy* db_tracker_thread) |
: is_initialized_(false), |
is_incognito_(is_incognito), |
+ clear_local_state_on_exit_(clear_local_state_on_exit), |
shutting_down_(false), |
profile_path_(profile_path), |
db_dir_(is_incognito_ ? |
@@ -102,6 +109,7 @@ DatabaseTracker::DatabaseTracker( |
meta_table_(NULL), |
special_storage_policy_(special_storage_policy), |
quota_manager_proxy_(quota_manager_proxy), |
+ db_tracker_thread_(db_tracker_thread), |
incognito_origin_directories_generator_(0) { |
if (quota_manager_proxy) { |
quota_manager_proxy->RegisterClient( |
@@ -119,7 +127,7 @@ void DatabaseTracker::DatabaseOpened(const string16& origin_identifier, |
const string16& database_description, |
int64 estimated_size, |
int64* database_size) { |
- if (!LazyInit()) { |
+ if (shutting_down_ || !LazyInit()) { |
*database_size = 0; |
return; |
} |
@@ -363,17 +371,18 @@ bool DatabaseTracker::DeleteClosedDatabase(const string16& origin_identifier, |
if (databases_table_->GetAllDatabaseDetailsForOrigin( |
origin_identifier, &details) && details.empty()) { |
// Try to delete the origin in case this was the last database. |
- DeleteOrigin(origin_identifier); |
+ DeleteOrigin(origin_identifier, false); |
} |
return true; |
} |
-bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier) { |
+bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier, |
+ bool force) { |
if (!LazyInit()) |
return false; |
// Check if any database in this origin is opened by any renderer. |
- if (database_connections_.IsOriginUsed(origin_identifier)) |
+ if (database_connections_.IsOriginUsed(origin_identifier) && !force) |
return false; |
int64 deleted_size = 0; |
@@ -383,14 +392,28 @@ bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier) { |
deleted_size = origin_info->TotalSize(); |
} |
- // We need to invalidate the cached record whether file_util::Delete() |
- // succeeds or not, because even if it fails, it might still delete some |
- // DB files on the hard drive. |
origins_info_map_.erase(origin_identifier); |
FilePath origin_dir = db_dir_.Append(FilePath::FromWStringHack( |
UTF16ToWide(origin_identifier))); |
- if (!file_util::Delete(origin_dir, true)) |
- return false; |
+ |
+ // Create a temporary directory to move possibly still existing databases to, |
+ // as we can't delete the origin directory on windows if it contains opened |
+ // files. |
+ FilePath new_origin_dir; |
+ file_util::CreateTemporaryDirInDir(db_dir_, |
+ kTemporaryDirectoryPrefix, |
+ &new_origin_dir); |
+ file_util::FileEnumerator databases( |
+ origin_dir, |
+ false, |
+ file_util::FileEnumerator::FILES); |
+ for (FilePath database = databases.Next(); !database.empty(); |
+ database = databases.Next()) { |
+ FilePath new_file = new_origin_dir.Append(database.BaseName()); |
+ file_util::Move(database, new_file); |
+ } |
+ file_util::Delete(origin_dir, true); |
+ file_util::Delete(new_origin_dir, true); // might fail on windows. |
databases_table_->DeleteOrigin(origin_identifier); |
@@ -422,6 +445,20 @@ bool DatabaseTracker::LazyInit() { |
DCHECK(!databases_table_.get()); |
DCHECK(!meta_table_.get()); |
+ // If there are left-over directories from failed deletion attempts, clean |
+ // them up. |
+ if (file_util::DirectoryExists(db_dir_)) { |
+ file_util::FileEnumerator directories( |
+ db_dir_, |
+ false, |
+ file_util::FileEnumerator::DIRECTORIES, |
+ kTemporaryDirectoryPattern); |
+ for (FilePath directory = directories.Next(); !directory.empty(); |
+ directory = directories.Next()) { |
+ file_util::Delete(directory, true); |
+ } |
+ } |
+ |
// If the tracker database exists, but it's corrupt or doesn't |
// have a meta table, delete the database directory. |
const FilePath kTrackerDatabaseFullPath = |
@@ -747,44 +784,67 @@ void DatabaseTracker::DeleteIncognitoDBDirectory() { |
file_util::Delete(incognito_db_dir, true); |
} |
-// static |
-void DatabaseTracker::ClearLocalState(const FilePath& profile_path) { |
- // TODO(michaeln): use SpecialStoragePolicy instead of kExtensionOriginPrefix |
- FilePath db_dir = profile_path.Append(FilePath(kDatabaseDirectoryName)); |
- FilePath db_tracker = db_dir.Append(FilePath(kTrackerDatabaseFileName)); |
- if (file_util::DirectoryExists(db_dir) && |
- file_util::PathExists(db_tracker)) { |
- scoped_ptr<sql::Connection> db_(new sql::Connection); |
- if (!db_->Open(db_tracker) || |
- !db_->DoesTableExist("Databases")) { |
- db_->Close(); |
- file_util::Delete(db_dir, true); |
- return; |
- } else { |
- sql::Statement delete_statement(db_->GetCachedStatement( |
- SQL_FROM_HERE, "DELETE FROM Databases WHERE origin NOT LIKE ?")); |
- std::string filter(kExtensionOriginIdentifierPrefix); |
- filter += "%"; |
- delete_statement.BindString(0, filter); |
- if (!delete_statement.Run()) { |
- db_->Close(); |
- file_util::Delete(db_dir, true); |
- return; |
- } |
+void DatabaseTracker::ClearLocalState() { |
+ shutting_down_ = true; |
+ |
+ std::vector<string16> origin_identifiers; |
+ GetAllOriginIdentifiers(&origin_identifiers); |
+ |
+ for (std::vector<string16>::iterator origin = origin_identifiers.begin(); |
+ origin != origin_identifiers.end(); ++origin) { |
+ if (special_storage_policy_.get() && |
+ special_storage_policy_->IsStorageProtected( |
+ webkit_database::DatabaseUtil::GetOriginFromIdentifier(*origin))) { |
+ continue; |
} |
- } |
- file_util::FileEnumerator file_enumerator(db_dir, false, |
- file_util::FileEnumerator::DIRECTORIES); |
- for (FilePath file_path = file_enumerator.Next(); !file_path.empty(); |
- file_path = file_enumerator.Next()) { |
- if (file_path.BaseName() != FilePath(kTrackerDatabaseFileName)) { |
- std::string basename = file_path.BaseName().MaybeAsASCII(); |
- if (!basename.empty() && |
- !StartsWithASCII(basename, kExtensionOriginIdentifierPrefix, true)) { |
- file_util::Delete(file_path, true); |
- } |
+ webkit_database::OriginInfo origin_info; |
+ std::vector<string16> databases; |
+ GetOriginInfo(*origin, &origin_info); |
+ origin_info.GetAllDatabaseNames(&databases); |
+ |
+ for (std::vector<string16>::iterator database = databases.begin(); |
+ database != databases.end(); ++database) { |
+ base::PlatformFile file_handle = base::CreatePlatformFile( |
+ GetFullDBFilePath(*origin, *database), |
+ base::PLATFORM_FILE_OPEN_ALWAYS | |
+ base::PLATFORM_FILE_SHARE_DELETE | |
+ base::PLATFORM_FILE_DELETE_ON_CLOSE | |
+ base::PLATFORM_FILE_READ, |
+ NULL, NULL); |
+ base::ClosePlatformFile(file_handle); |
} |
+ DeleteOrigin(*origin, true); |
+ } |
+} |
+ |
+ |
+void DatabaseTracker::Shutdown() { |
+ DCHECK(db_tracker_thread_.get()); |
+ DCHECK(db_tracker_thread_->BelongsToCurrentThread()); |
+ if (shutting_down_) { |
+ NOTREACHED(); |
+ return; |
+ } |
+ if (is_incognito_) |
+ DeleteIncognitoDBDirectory(); |
+ else if (clear_local_state_on_exit_ && LazyInit()) |
+ ClearLocalState(); |
+} |
+ |
+void DatabaseTracker::SetClearLocalStateOnExit(bool clear_local_state_on_exit) { |
+ DCHECK(db_tracker_thread_.get()); |
+ if (!db_tracker_thread_->BelongsToCurrentThread()) { |
+ db_tracker_thread_->PostTask(FROM_HERE, |
+ NewRunnableMethod(this, |
+ &DatabaseTracker::SetClearLocalStateOnExit, |
+ clear_local_state_on_exit)); |
+ return; |
+ } |
+ if (shutting_down_) { |
+ NOTREACHED(); |
+ return; |
} |
+ clear_local_state_on_exit_ = clear_local_state_on_exit; |
} |
} // namespace webkit_database |