Revert "Merged all Chromoting Host code into remoting_core.dll (Windows)."
[chromium-blink-merge.git] / webkit / database / database_tracker.cc
blob824c8a2fe57f5080bcd50fb2ffc8caf899f38fed
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "webkit/database/database_tracker.h"
7 #include <algorithm>
8 #include <vector>
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/file_util.h"
13 #include "base/message_loop_proxy.h"
14 #include "base/platform_file.h"
15 #include "base/string_number_conversions.h"
16 #include "base/utf_string_conversions.h"
17 #include "net/base/net_errors.h"
18 #include "sql/connection.h"
19 #include "sql/meta_table.h"
20 #include "sql/transaction.h"
21 #include "third_party/sqlite/sqlite3.h"
22 #include "webkit/database/database_quota_client.h"
23 #include "webkit/database/database_util.h"
24 #include "webkit/database/databases_table.h"
25 #include "webkit/quota/quota_manager.h"
26 #include "webkit/quota/special_storage_policy.h"
28 namespace webkit_database {
30 const FilePath::CharType kDatabaseDirectoryName[] =
31 FILE_PATH_LITERAL("databases");
32 const FilePath::CharType kIncognitoDatabaseDirectoryName[] =
33 FILE_PATH_LITERAL("databases-incognito");
34 const FilePath::CharType kTrackerDatabaseFileName[] =
35 FILE_PATH_LITERAL("Databases.db");
36 static const int kCurrentVersion = 2;
37 static const int kCompatibleVersion = 1;
39 const FilePath::CharType kTemporaryDirectoryPrefix[] =
40 FILE_PATH_LITERAL("DeleteMe");
41 const FilePath::CharType kTemporaryDirectoryPattern[] =
42 FILE_PATH_LITERAL("DeleteMe*");
44 OriginInfo::OriginInfo()
45 : total_size_(0) {}
47 OriginInfo::OriginInfo(const OriginInfo& origin_info)
48 : origin_(origin_info.origin_),
49 total_size_(origin_info.total_size_),
50 database_info_(origin_info.database_info_) {}
52 OriginInfo::~OriginInfo() {}
54 void OriginInfo::GetAllDatabaseNames(std::vector<string16>* databases) const {
55 for (DatabaseInfoMap::const_iterator it = database_info_.begin();
56 it != database_info_.end(); it++) {
57 databases->push_back(it->first);
61 int64 OriginInfo::GetDatabaseSize(const string16& database_name) const {
62 DatabaseInfoMap::const_iterator it = database_info_.find(database_name);
63 if (it != database_info_.end())
64 return it->second.first;
65 return 0;
68 string16 OriginInfo::GetDatabaseDescription(
69 const string16& database_name) const {
70 DatabaseInfoMap::const_iterator it = database_info_.find(database_name);
71 if (it != database_info_.end())
72 return it->second.second;
73 return string16();
76 OriginInfo::OriginInfo(const string16& origin, int64 total_size)
77 : origin_(origin), total_size_(total_size) {}
79 DatabaseTracker::DatabaseTracker(
80 const FilePath& profile_path,
81 bool is_incognito,
82 quota::SpecialStoragePolicy* special_storage_policy,
83 quota::QuotaManagerProxy* quota_manager_proxy,
84 base::MessageLoopProxy* db_tracker_thread)
85 : is_initialized_(false),
86 is_incognito_(is_incognito),
87 force_keep_session_state_(false),
88 shutting_down_(false),
89 profile_path_(profile_path),
90 db_dir_(is_incognito_ ?
91 profile_path_.Append(kIncognitoDatabaseDirectoryName) :
92 profile_path_.Append(kDatabaseDirectoryName)),
93 db_(new sql::Connection()),
94 databases_table_(NULL),
95 meta_table_(NULL),
96 special_storage_policy_(special_storage_policy),
97 quota_manager_proxy_(quota_manager_proxy),
98 db_tracker_thread_(db_tracker_thread),
99 incognito_origin_directories_generator_(0) {
100 if (quota_manager_proxy) {
101 quota_manager_proxy->RegisterClient(
102 new DatabaseQuotaClient(db_tracker_thread, this));
106 DatabaseTracker::~DatabaseTracker() {
107 DCHECK(dbs_to_be_deleted_.empty());
108 DCHECK(deletion_callbacks_.empty());
111 void DatabaseTracker::DatabaseOpened(const string16& origin_identifier,
112 const string16& database_name,
113 const string16& database_description,
114 int64 estimated_size,
115 int64* database_size) {
116 if (shutting_down_ || !LazyInit()) {
117 *database_size = 0;
118 return;
121 if (quota_manager_proxy_)
122 quota_manager_proxy_->NotifyStorageAccessed(
123 quota::QuotaClient::kDatabase,
124 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
125 quota::kStorageTypeTemporary);
127 InsertOrUpdateDatabaseDetails(origin_identifier, database_name,
128 database_description, estimated_size);
129 if (database_connections_.AddConnection(origin_identifier, database_name)) {
130 *database_size = SeedOpenDatabaseInfo(origin_identifier,
131 database_name,
132 database_description);
133 return;
135 *database_size = UpdateOpenDatabaseInfoAndNotify(origin_identifier,
136 database_name,
137 &database_description);
140 void DatabaseTracker::DatabaseModified(const string16& origin_identifier,
141 const string16& database_name) {
142 if (!LazyInit())
143 return;
144 UpdateOpenDatabaseSizeAndNotify(origin_identifier, database_name);
147 void DatabaseTracker::DatabaseClosed(const string16& origin_identifier,
148 const string16& database_name) {
149 if (database_connections_.IsEmpty()) {
150 DCHECK(!is_initialized_);
151 return;
154 // We call NotifiyStorageAccessed when a db is opened and also when
155 // closed because we don't call it for read while open.
156 if (quota_manager_proxy_)
157 quota_manager_proxy_->NotifyStorageAccessed(
158 quota::QuotaClient::kDatabase,
159 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
160 quota::kStorageTypeTemporary);
162 UpdateOpenDatabaseSizeAndNotify(origin_identifier, database_name);
163 if (database_connections_.RemoveConnection(origin_identifier, database_name))
164 DeleteDatabaseIfNeeded(origin_identifier, database_name);
167 void DatabaseTracker::HandleSqliteError(
168 const string16& origin_identifier,
169 const string16& database_name,
170 int error) {
171 // We only handle errors that indicate corruption and we
172 // do so with a heavy hand, we delete it. Any renderers/workers
173 // with this database open will receive a message to close it
174 // immediately, once all have closed, the files will be deleted.
175 // In the interim, all attempts to open a new connection to that
176 // database will fail.
177 // Note: the client-side filters out all but these two errors as
178 // a small optimization, see WebDatabaseObserverImpl::HandleSqliteError.
179 if (error == SQLITE_CORRUPT || error == SQLITE_NOTADB) {
180 DeleteDatabase(origin_identifier, database_name,
181 net::CompletionCallback());
185 void DatabaseTracker::CloseDatabases(const DatabaseConnections& connections) {
186 if (database_connections_.IsEmpty()) {
187 DCHECK(!is_initialized_ || connections.IsEmpty());
188 return;
191 // When being closed by this route, there's a chance that
192 // the tracker missed some DatabseModified calls. This method is used
193 // when a renderer crashes to cleanup its open resources.
194 // We need to examine what we have in connections for the
195 // size of each open databases and notify any differences between the
196 // actual file sizes now.
197 std::vector<std::pair<string16, string16> > open_dbs;
198 connections.ListConnections(&open_dbs);
199 for (std::vector<std::pair<string16, string16> >::iterator it =
200 open_dbs.begin(); it != open_dbs.end(); ++it)
201 UpdateOpenDatabaseSizeAndNotify(it->first, it->second);
203 std::vector<std::pair<string16, string16> > closed_dbs;
204 database_connections_.RemoveConnections(connections, &closed_dbs);
205 for (std::vector<std::pair<string16, string16> >::iterator it =
206 closed_dbs.begin(); it != closed_dbs.end(); ++it) {
207 DeleteDatabaseIfNeeded(it->first, it->second);
211 void DatabaseTracker::DeleteDatabaseIfNeeded(const string16& origin_identifier,
212 const string16& database_name) {
213 DCHECK(!database_connections_.IsDatabaseOpened(origin_identifier,
214 database_name));
215 if (IsDatabaseScheduledForDeletion(origin_identifier, database_name)) {
216 DeleteClosedDatabase(origin_identifier, database_name);
217 dbs_to_be_deleted_[origin_identifier].erase(database_name);
218 if (dbs_to_be_deleted_[origin_identifier].empty())
219 dbs_to_be_deleted_.erase(origin_identifier);
221 PendingDeletionCallbacks::iterator callback = deletion_callbacks_.begin();
222 while (callback != deletion_callbacks_.end()) {
223 DatabaseSet::iterator found_origin =
224 callback->second.find(origin_identifier);
225 if (found_origin != callback->second.end()) {
226 std::set<string16>& databases = found_origin->second;
227 databases.erase(database_name);
228 if (databases.empty()) {
229 callback->second.erase(found_origin);
230 if (callback->second.empty()) {
231 net::CompletionCallback cb = callback->first;
232 cb.Run(net::OK);
233 callback = deletion_callbacks_.erase(callback);
234 continue;
239 ++callback;
244 void DatabaseTracker::AddObserver(Observer* observer) {
245 observers_.AddObserver(observer);
248 void DatabaseTracker::RemoveObserver(Observer* observer) {
249 // When we remove a listener, we do not know which cached information
250 // is still needed and which information can be discarded. So we just
251 // clear all caches and re-populate them as needed.
252 observers_.RemoveObserver(observer);
253 ClearAllCachedOriginInfo();
256 void DatabaseTracker::CloseTrackerDatabaseAndClearCaches() {
257 ClearAllCachedOriginInfo();
259 if (!is_incognito_) {
260 meta_table_.reset(NULL);
261 databases_table_.reset(NULL);
262 db_->Close();
263 is_initialized_ = false;
267 string16 DatabaseTracker::GetOriginDirectory(
268 const string16& origin_identifier) {
269 if (!is_incognito_)
270 return origin_identifier;
272 OriginDirectoriesMap::const_iterator it =
273 incognito_origin_directories_.find(origin_identifier);
274 if (it != incognito_origin_directories_.end())
275 return it->second;
277 string16 origin_directory =
278 base::IntToString16(incognito_origin_directories_generator_++);
279 incognito_origin_directories_[origin_identifier] = origin_directory;
280 return origin_directory;
283 FilePath DatabaseTracker::GetFullDBFilePath(
284 const string16& origin_identifier,
285 const string16& database_name) {
286 DCHECK(!origin_identifier.empty());
287 if (!LazyInit())
288 return FilePath();
290 int64 id = databases_table_->GetDatabaseID(
291 origin_identifier, database_name);
292 if (id < 0)
293 return FilePath();
295 FilePath file_name = FilePath::FromWStringHack(
296 UTF8ToWide(base::Int64ToString(id)));
297 return db_dir_.Append(FilePath::FromWStringHack(
298 UTF16ToWide(GetOriginDirectory(origin_identifier)))).Append(file_name);
301 bool DatabaseTracker::GetOriginInfo(const string16& origin_identifier,
302 OriginInfo* info) {
303 DCHECK(info);
304 CachedOriginInfo* cached_info = GetCachedOriginInfo(origin_identifier);
305 if (!cached_info)
306 return false;
307 *info = OriginInfo(*cached_info);
308 return true;
311 bool DatabaseTracker::GetAllOriginIdentifiers(
312 std::vector<string16>* origin_identifiers) {
313 DCHECK(origin_identifiers);
314 DCHECK(origin_identifiers->empty());
315 if (!LazyInit())
316 return false;
317 return databases_table_->GetAllOrigins(origin_identifiers);
320 bool DatabaseTracker::GetAllOriginsInfo(std::vector<OriginInfo>* origins_info) {
321 DCHECK(origins_info);
322 DCHECK(origins_info->empty());
324 std::vector<string16> origins;
325 if (!GetAllOriginIdentifiers(&origins))
326 return false;
328 for (std::vector<string16>::const_iterator it = origins.begin();
329 it != origins.end(); it++) {
330 CachedOriginInfo* origin_info = GetCachedOriginInfo(*it);
331 if (!origin_info) {
332 // Restore 'origins_info' to its initial state.
333 origins_info->clear();
334 return false;
336 origins_info->push_back(OriginInfo(*origin_info));
339 return true;
342 bool DatabaseTracker::DeleteClosedDatabase(const string16& origin_identifier,
343 const string16& database_name) {
344 if (!LazyInit())
345 return false;
347 // Check if the database is opened by any renderer.
348 if (database_connections_.IsDatabaseOpened(origin_identifier, database_name))
349 return false;
351 int64 db_file_size = quota_manager_proxy_ ?
352 GetDBFileSize(origin_identifier, database_name) : 0;
354 // Try to delete the file on the hard drive.
355 FilePath db_file = GetFullDBFilePath(origin_identifier, database_name);
356 if (file_util::PathExists(db_file) && !file_util::Delete(db_file, false))
357 return false;
359 // Also delete any orphaned journal file.
360 DCHECK(db_file.Extension().empty());
361 file_util::Delete(db_file.InsertBeforeExtensionASCII(
362 DatabaseUtil::kJournalFileSuffix), false);
364 if (quota_manager_proxy_ && db_file_size)
365 quota_manager_proxy_->NotifyStorageModified(
366 quota::QuotaClient::kDatabase,
367 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
368 quota::kStorageTypeTemporary,
369 -db_file_size);
371 // Clean up the main database and invalidate the cached record.
372 databases_table_->DeleteDatabaseDetails(origin_identifier, database_name);
373 origins_info_map_.erase(origin_identifier);
375 std::vector<DatabaseDetails> details;
376 if (databases_table_->GetAllDatabaseDetailsForOrigin(
377 origin_identifier, &details) && details.empty()) {
378 // Try to delete the origin in case this was the last database.
379 DeleteOrigin(origin_identifier, false);
381 return true;
384 bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier,
385 bool force) {
386 if (!LazyInit())
387 return false;
389 // Check if any database in this origin is opened by any renderer.
390 if (database_connections_.IsOriginUsed(origin_identifier) && !force)
391 return false;
393 int64 deleted_size = 0;
394 if (quota_manager_proxy_) {
395 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier);
396 if (origin_info)
397 deleted_size = origin_info->TotalSize();
400 origins_info_map_.erase(origin_identifier);
401 FilePath origin_dir = db_dir_.Append(FilePath::FromWStringHack(
402 UTF16ToWide(origin_identifier)));
404 // Create a temporary directory to move possibly still existing databases to,
405 // as we can't delete the origin directory on windows if it contains opened
406 // files.
407 FilePath new_origin_dir;
408 file_util::CreateTemporaryDirInDir(db_dir_,
409 kTemporaryDirectoryPrefix,
410 &new_origin_dir);
411 file_util::FileEnumerator databases(
412 origin_dir,
413 false,
414 file_util::FileEnumerator::FILES);
415 for (FilePath database = databases.Next(); !database.empty();
416 database = databases.Next()) {
417 FilePath new_file = new_origin_dir.Append(database.BaseName());
418 file_util::Move(database, new_file);
420 file_util::Delete(origin_dir, true);
421 file_util::Delete(new_origin_dir, true); // might fail on windows.
423 databases_table_->DeleteOrigin(origin_identifier);
425 if (quota_manager_proxy_ && deleted_size) {
426 quota_manager_proxy_->NotifyStorageModified(
427 quota::QuotaClient::kDatabase,
428 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
429 quota::kStorageTypeTemporary,
430 -deleted_size);
433 return true;
436 bool DatabaseTracker::IsDatabaseScheduledForDeletion(
437 const string16& origin_identifier,
438 const string16& database_name) {
439 DatabaseSet::iterator it = dbs_to_be_deleted_.find(origin_identifier);
440 if (it == dbs_to_be_deleted_.end())
441 return false;
443 std::set<string16>& databases = it->second;
444 return (databases.find(database_name) != databases.end());
447 bool DatabaseTracker::LazyInit() {
448 if (!is_initialized_ && !shutting_down_) {
449 DCHECK(!db_->is_open());
450 DCHECK(!databases_table_.get());
451 DCHECK(!meta_table_.get());
453 // If there are left-over directories from failed deletion attempts, clean
454 // them up.
455 if (file_util::DirectoryExists(db_dir_)) {
456 file_util::FileEnumerator directories(
457 db_dir_,
458 false,
459 file_util::FileEnumerator::DIRECTORIES,
460 kTemporaryDirectoryPattern);
461 for (FilePath directory = directories.Next(); !directory.empty();
462 directory = directories.Next()) {
463 file_util::Delete(directory, true);
467 // If the tracker database exists, but it's corrupt or doesn't
468 // have a meta table, delete the database directory.
469 const FilePath kTrackerDatabaseFullPath =
470 db_dir_.Append(FilePath(kTrackerDatabaseFileName));
471 if (file_util::DirectoryExists(db_dir_) &&
472 file_util::PathExists(kTrackerDatabaseFullPath) &&
473 (!db_->Open(kTrackerDatabaseFullPath) ||
474 !sql::MetaTable::DoesTableExist(db_.get()))) {
475 db_->Close();
476 if (!file_util::Delete(db_dir_, true))
477 return false;
480 db_->set_error_histogram_name("Sqlite.DatabaseTracker.Error");
482 databases_table_.reset(new DatabasesTable(db_.get()));
483 meta_table_.reset(new sql::MetaTable());
485 is_initialized_ =
486 file_util::CreateDirectory(db_dir_) &&
487 (db_->is_open() ||
488 (is_incognito_ ? db_->OpenInMemory() :
489 db_->Open(kTrackerDatabaseFullPath))) &&
490 UpgradeToCurrentVersion();
491 if (!is_initialized_) {
492 databases_table_.reset(NULL);
493 meta_table_.reset(NULL);
494 db_->Close();
497 return is_initialized_;
500 bool DatabaseTracker::UpgradeToCurrentVersion() {
501 sql::Transaction transaction(db_.get());
502 if (!transaction.Begin() ||
503 !meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion) ||
504 (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) ||
505 !databases_table_->Init())
506 return false;
508 if (meta_table_->GetVersionNumber() < kCurrentVersion)
509 meta_table_->SetVersionNumber(kCurrentVersion);
511 return transaction.Commit();
514 void DatabaseTracker::InsertOrUpdateDatabaseDetails(
515 const string16& origin_identifier,
516 const string16& database_name,
517 const string16& database_description,
518 int64 estimated_size) {
519 DatabaseDetails details;
520 if (!databases_table_->GetDatabaseDetails(
521 origin_identifier, database_name, &details)) {
522 details.origin_identifier = origin_identifier;
523 details.database_name = database_name;
524 details.description = database_description;
525 details.estimated_size = estimated_size;
526 databases_table_->InsertDatabaseDetails(details);
527 } else if ((details.description != database_description) ||
528 (details.estimated_size != estimated_size)) {
529 details.description = database_description;
530 details.estimated_size = estimated_size;
531 databases_table_->UpdateDatabaseDetails(details);
535 void DatabaseTracker::ClearAllCachedOriginInfo() {
536 origins_info_map_.clear();
539 DatabaseTracker::CachedOriginInfo* DatabaseTracker::MaybeGetCachedOriginInfo(
540 const string16& origin_identifier, bool create_if_needed) {
541 if (!LazyInit())
542 return NULL;
544 // Populate the cache with data for this origin if needed.
545 if (origins_info_map_.find(origin_identifier) == origins_info_map_.end()) {
546 if (!create_if_needed)
547 return NULL;
549 std::vector<DatabaseDetails> details;
550 if (!databases_table_->GetAllDatabaseDetailsForOrigin(
551 origin_identifier, &details)) {
552 return NULL;
555 CachedOriginInfo& origin_info = origins_info_map_[origin_identifier];
556 origin_info.SetOrigin(origin_identifier);
557 for (std::vector<DatabaseDetails>::const_iterator it = details.begin();
558 it != details.end(); it++) {
559 int64 db_file_size;
560 if (database_connections_.IsDatabaseOpened(
561 origin_identifier, it->database_name)) {
562 db_file_size = database_connections_.GetOpenDatabaseSize(
563 origin_identifier, it->database_name);
564 } else {
565 db_file_size = GetDBFileSize(origin_identifier, it->database_name);
567 origin_info.SetDatabaseSize(it->database_name, db_file_size);
568 origin_info.SetDatabaseDescription(it->database_name, it->description);
572 return &origins_info_map_[origin_identifier];
575 int64 DatabaseTracker::GetDBFileSize(const string16& origin_identifier,
576 const string16& database_name) {
577 FilePath db_file_name = GetFullDBFilePath(origin_identifier, database_name);
578 int64 db_file_size = 0;
579 if (!file_util::GetFileSize(db_file_name, &db_file_size))
580 db_file_size = 0;
581 return db_file_size;
584 int64 DatabaseTracker::SeedOpenDatabaseInfo(
585 const string16& origin_id, const string16& name,
586 const string16& description) {
587 DCHECK(database_connections_.IsDatabaseOpened(origin_id, name));
588 int64 size = GetDBFileSize(origin_id, name);
589 database_connections_.SetOpenDatabaseSize(origin_id, name, size);
590 CachedOriginInfo* info = MaybeGetCachedOriginInfo(origin_id, false);
591 if (info) {
592 info->SetDatabaseSize(name, size);
593 info->SetDatabaseDescription(name, description);
595 return size;
598 int64 DatabaseTracker::UpdateOpenDatabaseInfoAndNotify(
599 const string16& origin_id, const string16& name,
600 const string16* opt_description) {
601 DCHECK(database_connections_.IsDatabaseOpened(origin_id, name));
602 int64 new_size = GetDBFileSize(origin_id, name);
603 int64 old_size = database_connections_.GetOpenDatabaseSize(origin_id, name);
604 CachedOriginInfo* info = MaybeGetCachedOriginInfo(origin_id, false);
605 if (info && opt_description)
606 info->SetDatabaseDescription(name, *opt_description);
607 if (old_size != new_size) {
608 database_connections_.SetOpenDatabaseSize(origin_id, name, new_size);
609 if (info)
610 info->SetDatabaseSize(name, new_size);
611 if (quota_manager_proxy_)
612 quota_manager_proxy_->NotifyStorageModified(
613 quota::QuotaClient::kDatabase,
614 DatabaseUtil::GetOriginFromIdentifier(origin_id),
615 quota::kStorageTypeTemporary,
616 new_size - old_size);
617 FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseSizeChanged(
618 origin_id, name, new_size));
620 return new_size;
623 void DatabaseTracker::ScheduleDatabaseForDeletion(
624 const string16& origin_identifier,
625 const string16& database_name) {
626 DCHECK(database_connections_.IsDatabaseOpened(origin_identifier,
627 database_name));
628 dbs_to_be_deleted_[origin_identifier].insert(database_name);
629 FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseScheduledForDeletion(
630 origin_identifier, database_name));
633 void DatabaseTracker::ScheduleDatabasesForDeletion(
634 const DatabaseSet& databases,
635 const net::CompletionCallback& callback) {
636 DCHECK(!databases.empty());
638 if (!callback.is_null())
639 deletion_callbacks_.push_back(std::make_pair(callback, databases));
640 for (DatabaseSet::const_iterator ori = databases.begin();
641 ori != databases.end(); ++ori) {
642 for (std::set<string16>::const_iterator db = ori->second.begin();
643 db != ori->second.end(); ++db)
644 ScheduleDatabaseForDeletion(ori->first, *db);
648 int DatabaseTracker::DeleteDatabase(const string16& origin_identifier,
649 const string16& database_name,
650 const net::CompletionCallback& callback) {
651 if (!LazyInit())
652 return net::ERR_FAILED;
654 if (database_connections_.IsDatabaseOpened(origin_identifier,
655 database_name)) {
656 if (!callback.is_null()) {
657 DatabaseSet set;
658 set[origin_identifier].insert(database_name);
659 deletion_callbacks_.push_back(std::make_pair(callback, set));
661 ScheduleDatabaseForDeletion(origin_identifier, database_name);
662 return net::ERR_IO_PENDING;
664 DeleteClosedDatabase(origin_identifier, database_name);
665 return net::OK;
668 int DatabaseTracker::DeleteDataModifiedSince(
669 const base::Time& cutoff,
670 const net::CompletionCallback& callback) {
671 if (!LazyInit())
672 return net::ERR_FAILED;
674 DatabaseSet to_be_deleted;
676 std::vector<string16> origins_identifiers;
677 if (!databases_table_->GetAllOrigins(&origins_identifiers))
678 return net::ERR_FAILED;
679 int rv = net::OK;
680 for (std::vector<string16>::const_iterator ori = origins_identifiers.begin();
681 ori != origins_identifiers.end(); ++ori) {
682 if (special_storage_policy_.get() &&
683 special_storage_policy_->IsStorageProtected(
684 DatabaseUtil::GetOriginFromIdentifier(*ori))) {
685 continue;
688 std::vector<DatabaseDetails> details;
689 if (!databases_table_->GetAllDatabaseDetailsForOrigin(*ori, &details))
690 rv = net::ERR_FAILED;
691 for (std::vector<DatabaseDetails>::const_iterator db = details.begin();
692 db != details.end(); ++db) {
693 FilePath db_file = GetFullDBFilePath(*ori, db->database_name);
694 base::PlatformFileInfo file_info;
695 file_util::GetFileInfo(db_file, &file_info);
696 if (file_info.last_modified < cutoff)
697 continue;
699 // Check if the database is opened by any renderer.
700 if (database_connections_.IsDatabaseOpened(*ori, db->database_name))
701 to_be_deleted[*ori].insert(db->database_name);
702 else
703 DeleteClosedDatabase(*ori, db->database_name);
707 if (rv != net::OK)
708 return rv;
710 if (!to_be_deleted.empty()) {
711 ScheduleDatabasesForDeletion(to_be_deleted, callback);
712 return net::ERR_IO_PENDING;
714 return net::OK;
717 int DatabaseTracker::DeleteDataForOrigin(
718 const string16& origin, const net::CompletionCallback& callback) {
719 if (!LazyInit())
720 return net::ERR_FAILED;
722 DatabaseSet to_be_deleted;
724 std::vector<DatabaseDetails> details;
725 if (!databases_table_->GetAllDatabaseDetailsForOrigin(origin, &details))
726 return net::ERR_FAILED;
727 for (std::vector<DatabaseDetails>::const_iterator db = details.begin();
728 db != details.end(); ++db) {
729 // Check if the database is opened by any renderer.
730 if (database_connections_.IsDatabaseOpened(origin, db->database_name))
731 to_be_deleted[origin].insert(db->database_name);
732 else
733 DeleteClosedDatabase(origin, db->database_name);
736 if (!to_be_deleted.empty()) {
737 ScheduleDatabasesForDeletion(to_be_deleted, callback);
738 return net::ERR_IO_PENDING;
740 return net::OK;
743 void DatabaseTracker::GetIncognitoFileHandle(
744 const string16& vfs_file_name, base::PlatformFile* file_handle) const {
745 DCHECK(is_incognito_);
746 FileHandlesMap::const_iterator it =
747 incognito_file_handles_.find(vfs_file_name);
748 if (it != incognito_file_handles_.end())
749 *file_handle = it->second;
750 else
751 *file_handle = base::kInvalidPlatformFileValue;
754 void DatabaseTracker::SaveIncognitoFileHandle(
755 const string16& vfs_file_name, const base::PlatformFile& file_handle) {
756 DCHECK(is_incognito_);
757 DCHECK(incognito_file_handles_.find(vfs_file_name) ==
758 incognito_file_handles_.end());
759 if (file_handle != base::kInvalidPlatformFileValue)
760 incognito_file_handles_[vfs_file_name] = file_handle;
763 bool DatabaseTracker::CloseIncognitoFileHandle(const string16& vfs_file_name) {
764 DCHECK(is_incognito_);
765 DCHECK(incognito_file_handles_.find(vfs_file_name) !=
766 incognito_file_handles_.end());
768 bool handle_closed = false;
769 FileHandlesMap::iterator it = incognito_file_handles_.find(vfs_file_name);
770 if (it != incognito_file_handles_.end()) {
771 handle_closed = base::ClosePlatformFile(it->second);
772 if (handle_closed)
773 incognito_file_handles_.erase(it);
775 return handle_closed;
778 bool DatabaseTracker::HasSavedIncognitoFileHandle(
779 const string16& vfs_file_name) const {
780 return (incognito_file_handles_.find(vfs_file_name) !=
781 incognito_file_handles_.end());
784 void DatabaseTracker::DeleteIncognitoDBDirectory() {
785 shutting_down_ = true;
786 is_initialized_ = false;
788 for (FileHandlesMap::iterator it = incognito_file_handles_.begin();
789 it != incognito_file_handles_.end(); it++)
790 base::ClosePlatformFile(it->second);
792 FilePath incognito_db_dir =
793 profile_path_.Append(kIncognitoDatabaseDirectoryName);
794 if (file_util::DirectoryExists(incognito_db_dir))
795 file_util::Delete(incognito_db_dir, true);
798 void DatabaseTracker::ClearSessionOnlyOrigins() {
799 shutting_down_ = true;
801 bool has_session_only_databases =
802 special_storage_policy_.get() &&
803 special_storage_policy_->HasSessionOnlyOrigins();
805 // Clearing only session-only databases, and there are none.
806 if (!has_session_only_databases)
807 return;
809 if (!LazyInit())
810 return;
812 std::vector<string16> origin_identifiers;
813 GetAllOriginIdentifiers(&origin_identifiers);
815 for (std::vector<string16>::iterator origin = origin_identifiers.begin();
816 origin != origin_identifiers.end(); ++origin) {
817 GURL origin_url =
818 webkit_database::DatabaseUtil::GetOriginFromIdentifier(*origin);
819 if (!special_storage_policy_->IsStorageSessionOnly(origin_url))
820 continue;
821 if (special_storage_policy_->IsStorageProtected(origin_url))
822 continue;
823 webkit_database::OriginInfo origin_info;
824 std::vector<string16> databases;
825 GetOriginInfo(*origin, &origin_info);
826 origin_info.GetAllDatabaseNames(&databases);
828 for (std::vector<string16>::iterator database = databases.begin();
829 database != databases.end(); ++database) {
830 base::PlatformFile file_handle = base::CreatePlatformFile(
831 GetFullDBFilePath(*origin, *database),
832 base::PLATFORM_FILE_OPEN_ALWAYS |
833 base::PLATFORM_FILE_SHARE_DELETE |
834 base::PLATFORM_FILE_DELETE_ON_CLOSE |
835 base::PLATFORM_FILE_READ,
836 NULL, NULL);
837 base::ClosePlatformFile(file_handle);
839 DeleteOrigin(*origin, true);
844 void DatabaseTracker::Shutdown() {
845 DCHECK(db_tracker_thread_.get());
846 DCHECK(db_tracker_thread_->BelongsToCurrentThread());
847 if (shutting_down_) {
848 NOTREACHED();
849 return;
851 if (is_incognito_)
852 DeleteIncognitoDBDirectory();
853 else if (!force_keep_session_state_)
854 ClearSessionOnlyOrigins();
857 void DatabaseTracker::SetForceKeepSessionState() {
858 DCHECK(db_tracker_thread_.get());
859 if (!db_tracker_thread_->BelongsToCurrentThread()) {
860 db_tracker_thread_->PostTask(
861 FROM_HERE,
862 base::Bind(&DatabaseTracker::SetForceKeepSessionState, this));
863 return;
865 force_keep_session_state_ = true;
868 } // namespace webkit_database