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. 4 5 #include "webkit/browser/database/database_tracker.h" 6 7 #include <algorithm> 8 #include <vector> 9 10 #include "base/basictypes.h" 11 #include "base/bind.h" 12 #include "base/file_util.h" 13 #include "base/files/file_enumerator.h" 14 #include "base/message_loop/message_loop_proxy.h" 15 #include "base/platform_file.h" 16 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/utf_string_conversions.h" 18 #include "net/base/net_errors.h" 19 #include "sql/connection.h" 20 #include "sql/meta_table.h" 21 #include "sql/transaction.h" 22 #include "third_party/sqlite/sqlite3.h" 23 #include "webkit/browser/database/database_quota_client.h" 24 #include "webkit/browser/database/database_util.h" 25 #include "webkit/browser/database/databases_table.h" 26 #include "webkit/browser/quota/quota_manager.h" 27 #include "webkit/browser/quota/special_storage_policy.h" 28 #include "webkit/common/database/database_identifier.h" 29 30 namespace webkit_database { 31 32 const base::FilePath::CharType kDatabaseDirectoryName[] = 33 FILE_PATH_LITERAL("databases"); 34 const base::FilePath::CharType kIncognitoDatabaseDirectoryName[] = 35 FILE_PATH_LITERAL("databases-incognito"); 36 const base::FilePath::CharType kTrackerDatabaseFileName[] = 37 FILE_PATH_LITERAL("Databases.db"); 38 static const int kCurrentVersion = 2; 39 static const int kCompatibleVersion = 1; 40 41 const base::FilePath::CharType kTemporaryDirectoryPrefix[] = 42 FILE_PATH_LITERAL("DeleteMe"); 43 const base::FilePath::CharType kTemporaryDirectoryPattern[] = 44 FILE_PATH_LITERAL("DeleteMe*"); 45 46 OriginInfo::OriginInfo() 47 : total_size_(0) {} 48 49 OriginInfo::OriginInfo(const OriginInfo& origin_info) 50 : origin_identifier_(origin_info.origin_identifier_), 51 total_size_(origin_info.total_size_), 52 database_info_(origin_info.database_info_) {} 53 54 OriginInfo::~OriginInfo() {} 55 56 void OriginInfo::GetAllDatabaseNames( 57 std::vector<base::string16>* databases) const { 58 for (DatabaseInfoMap::const_iterator it = database_info_.begin(); 59 it != database_info_.end(); it++) { 60 databases->push_back(it->first); 61 } 62 } 63 64 int64 OriginInfo::GetDatabaseSize(const base::string16& database_name) const { 65 DatabaseInfoMap::const_iterator it = database_info_.find(database_name); 66 if (it != database_info_.end()) 67 return it->second.first; 68 return 0; 69 } 70 71 base::string16 OriginInfo::GetDatabaseDescription( 72 const base::string16& database_name) const { 73 DatabaseInfoMap::const_iterator it = database_info_.find(database_name); 74 if (it != database_info_.end()) 75 return it->second.second; 76 return base::string16(); 77 } 78 79 OriginInfo::OriginInfo(const std::string& origin_identifier, int64 total_size) 80 : origin_identifier_(origin_identifier), total_size_(total_size) {} 81 82 DatabaseTracker::DatabaseTracker( 83 const base::FilePath& profile_path, 84 bool is_incognito, 85 quota::SpecialStoragePolicy* special_storage_policy, 86 quota::QuotaManagerProxy* quota_manager_proxy, 87 base::MessageLoopProxy* db_tracker_thread) 88 : is_initialized_(false), 89 is_incognito_(is_incognito), 90 force_keep_session_state_(false), 91 shutting_down_(false), 92 profile_path_(profile_path), 93 db_dir_(is_incognito_ 94 ? profile_path_.Append(kIncognitoDatabaseDirectoryName) 95 : profile_path_.Append(kDatabaseDirectoryName)), 96 db_(new sql::Connection()), 97 special_storage_policy_(special_storage_policy), 98 quota_manager_proxy_(quota_manager_proxy), 99 db_tracker_thread_(db_tracker_thread), 100 incognito_origin_directories_generator_(0) { 101 if (quota_manager_proxy) { 102 quota_manager_proxy->RegisterClient( 103 new DatabaseQuotaClient(db_tracker_thread, this)); 104 } 105 } 106 107 DatabaseTracker::~DatabaseTracker() { 108 DCHECK(dbs_to_be_deleted_.empty()); 109 DCHECK(deletion_callbacks_.empty()); 110 } 111 112 void DatabaseTracker::DatabaseOpened(const std::string& origin_identifier, 113 const base::string16& database_name, 114 const base::string16& database_description, 115 int64 estimated_size, 116 int64* database_size) { 117 if (shutting_down_ || !LazyInit()) { 118 *database_size = 0; 119 return; 120 } 121 122 if (quota_manager_proxy_.get()) 123 quota_manager_proxy_->NotifyStorageAccessed( 124 quota::QuotaClient::kDatabase, 125 webkit_database::GetOriginFromIdentifier(origin_identifier), 126 quota::kStorageTypeTemporary); 127 128 InsertOrUpdateDatabaseDetails(origin_identifier, database_name, 129 database_description, estimated_size); 130 if (database_connections_.AddConnection(origin_identifier, database_name)) { 131 *database_size = SeedOpenDatabaseInfo(origin_identifier, 132 database_name, 133 database_description); 134 return; 135 } 136 *database_size = UpdateOpenDatabaseInfoAndNotify(origin_identifier, 137 database_name, 138 &database_description); 139 } 140 141 void DatabaseTracker::DatabaseModified(const std::string& origin_identifier, 142 const base::string16& database_name) { 143 if (!LazyInit()) 144 return; 145 UpdateOpenDatabaseSizeAndNotify(origin_identifier, database_name); 146 } 147 148 void DatabaseTracker::DatabaseClosed(const std::string& origin_identifier, 149 const base::string16& database_name) { 150 if (database_connections_.IsEmpty()) { 151 DCHECK(!is_initialized_); 152 return; 153 } 154 155 // We call NotifiyStorageAccessed when a db is opened and also when 156 // closed because we don't call it for read while open. 157 if (quota_manager_proxy_.get()) 158 quota_manager_proxy_->NotifyStorageAccessed( 159 quota::QuotaClient::kDatabase, 160 webkit_database::GetOriginFromIdentifier(origin_identifier), 161 quota::kStorageTypeTemporary); 162 163 UpdateOpenDatabaseSizeAndNotify(origin_identifier, database_name); 164 if (database_connections_.RemoveConnection(origin_identifier, database_name)) 165 DeleteDatabaseIfNeeded(origin_identifier, database_name); 166 } 167 168 void DatabaseTracker::HandleSqliteError( 169 const std::string& origin_identifier, 170 const base::string16& database_name, 171 int error) { 172 // We only handle errors that indicate corruption and we 173 // do so with a heavy hand, we delete it. Any renderers/workers 174 // with this database open will receive a message to close it 175 // immediately, once all have closed, the files will be deleted. 176 // In the interim, all attempts to open a new connection to that 177 // database will fail. 178 // Note: the client-side filters out all but these two errors as 179 // a small optimization, see WebDatabaseObserverImpl::HandleSqliteError. 180 if (error == SQLITE_CORRUPT || error == SQLITE_NOTADB) { 181 DeleteDatabase(origin_identifier, database_name, 182 net::CompletionCallback()); 183 } 184 } 185 186 void DatabaseTracker::CloseDatabases(const DatabaseConnections& connections) { 187 if (database_connections_.IsEmpty()) { 188 DCHECK(!is_initialized_ || connections.IsEmpty()); 189 return; 190 } 191 192 // When being closed by this route, there's a chance that 193 // the tracker missed some DatabseModified calls. This method is used 194 // when a renderer crashes to cleanup its open resources. 195 // We need to examine what we have in connections for the 196 // size of each open databases and notify any differences between the 197 // actual file sizes now. 198 std::vector<std::pair<std::string, base::string16> > open_dbs; 199 connections.ListConnections(&open_dbs); 200 for (std::vector<std::pair<std::string, base::string16> >::iterator it = 201 open_dbs.begin(); it != open_dbs.end(); ++it) 202 UpdateOpenDatabaseSizeAndNotify(it->first, it->second); 203 204 std::vector<std::pair<std::string, base::string16> > closed_dbs; 205 database_connections_.RemoveConnections(connections, &closed_dbs); 206 for (std::vector<std::pair<std::string, base::string16> >::iterator it = 207 closed_dbs.begin(); it != closed_dbs.end(); ++it) { 208 DeleteDatabaseIfNeeded(it->first, it->second); 209 } 210 } 211 212 void DatabaseTracker::DeleteDatabaseIfNeeded( 213 const std::string& origin_identifier, 214 const base::string16& database_name) { 215 DCHECK(!database_connections_.IsDatabaseOpened(origin_identifier, 216 database_name)); 217 if (IsDatabaseScheduledForDeletion(origin_identifier, database_name)) { 218 DeleteClosedDatabase(origin_identifier, database_name); 219 dbs_to_be_deleted_[origin_identifier].erase(database_name); 220 if (dbs_to_be_deleted_[origin_identifier].empty()) 221 dbs_to_be_deleted_.erase(origin_identifier); 222 223 PendingDeletionCallbacks::iterator callback = deletion_callbacks_.begin(); 224 while (callback != deletion_callbacks_.end()) { 225 DatabaseSet::iterator found_origin = 226 callback->second.find(origin_identifier); 227 if (found_origin != callback->second.end()) { 228 std::set<base::string16>& databases = found_origin->second; 229 databases.erase(database_name); 230 if (databases.empty()) { 231 callback->second.erase(found_origin); 232 if (callback->second.empty()) { 233 net::CompletionCallback cb = callback->first; 234 cb.Run(net::OK); 235 callback = deletion_callbacks_.erase(callback); 236 continue; 237 } 238 } 239 } 240 241 ++callback; 242 } 243 } 244 } 245 246 void DatabaseTracker::AddObserver(Observer* observer) { 247 observers_.AddObserver(observer); 248 } 249 250 void DatabaseTracker::RemoveObserver(Observer* observer) { 251 // When we remove a listener, we do not know which cached information 252 // is still needed and which information can be discarded. So we just 253 // clear all caches and re-populate them as needed. 254 observers_.RemoveObserver(observer); 255 ClearAllCachedOriginInfo(); 256 } 257 258 void DatabaseTracker::CloseTrackerDatabaseAndClearCaches() { 259 ClearAllCachedOriginInfo(); 260 261 if (!is_incognito_) { 262 meta_table_.reset(NULL); 263 databases_table_.reset(NULL); 264 db_->Close(); 265 is_initialized_ = false; 266 } 267 } 268 269 base::string16 DatabaseTracker::GetOriginDirectory( 270 const std::string& origin_identifier) { 271 if (!is_incognito_) 272 return base::UTF8ToUTF16(origin_identifier); 273 274 OriginDirectoriesMap::const_iterator it = 275 incognito_origin_directories_.find(origin_identifier); 276 if (it != incognito_origin_directories_.end()) 277 return it->second; 278 279 base::string16 origin_directory = 280 base::IntToString16(incognito_origin_directories_generator_++); 281 incognito_origin_directories_[origin_identifier] = origin_directory; 282 return origin_directory; 283 } 284 285 base::FilePath DatabaseTracker::GetFullDBFilePath( 286 const std::string& origin_identifier, 287 const base::string16& database_name) { 288 DCHECK(!origin_identifier.empty()); 289 if (!LazyInit()) 290 return base::FilePath(); 291 292 int64 id = databases_table_->GetDatabaseID(origin_identifier, database_name); 293 if (id < 0) 294 return base::FilePath(); 295 296 return db_dir_.Append(base::FilePath::FromUTF16Unsafe( 297 GetOriginDirectory(origin_identifier))).AppendASCII( 298 base::Int64ToString(id)); 299 } 300 301 bool DatabaseTracker::GetOriginInfo(const std::string& 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; 309 } 310 311 bool DatabaseTracker::GetAllOriginIdentifiers( 312 std::vector<std::string>* origin_identifiers) { 313 DCHECK(origin_identifiers); 314 DCHECK(origin_identifiers->empty()); 315 if (!LazyInit()) 316 return false; 317 return databases_table_->GetAllOriginIdentifiers(origin_identifiers); 318 } 319 320 bool DatabaseTracker::GetAllOriginsInfo( 321 std::vector<OriginInfo>* origins_info) { 322 DCHECK(origins_info); 323 DCHECK(origins_info->empty()); 324 325 std::vector<std::string> origins; 326 if (!GetAllOriginIdentifiers(&origins)) 327 return false; 328 329 for (std::vector<std::string>::const_iterator it = origins.begin(); 330 it != origins.end(); it++) { 331 CachedOriginInfo* origin_info = GetCachedOriginInfo(*it); 332 if (!origin_info) { 333 // Restore 'origins_info' to its initial state. 334 origins_info->clear(); 335 return false; 336 } 337 origins_info->push_back(OriginInfo(*origin_info)); 338 } 339 340 return true; 341 } 342 343 bool DatabaseTracker::DeleteClosedDatabase( 344 const std::string& origin_identifier, 345 const base::string16& database_name) { 346 if (!LazyInit()) 347 return false; 348 349 // Check if the database is opened by any renderer. 350 if (database_connections_.IsDatabaseOpened(origin_identifier, database_name)) 351 return false; 352 353 int64 db_file_size = quota_manager_proxy_.get() 354 ? GetDBFileSize(origin_identifier, database_name) 355 : 0; 356 357 // Try to delete the file on the hard drive. 358 base::FilePath db_file = GetFullDBFilePath(origin_identifier, database_name); 359 if (!sql::Connection::Delete(db_file)) 360 return false; 361 362 if (quota_manager_proxy_.get() && db_file_size) 363 quota_manager_proxy_->NotifyStorageModified( 364 quota::QuotaClient::kDatabase, 365 webkit_database::GetOriginFromIdentifier(origin_identifier), 366 quota::kStorageTypeTemporary, 367 -db_file_size); 368 369 // Clean up the main database and invalidate the cached record. 370 databases_table_->DeleteDatabaseDetails(origin_identifier, database_name); 371 origins_info_map_.erase(origin_identifier); 372 373 std::vector<DatabaseDetails> details; 374 if (databases_table_->GetAllDatabaseDetailsForOriginIdentifier( 375 origin_identifier, &details) && details.empty()) { 376 // Try to delete the origin in case this was the last database. 377 DeleteOrigin(origin_identifier, false); 378 } 379 return true; 380 } 381 382 bool DatabaseTracker::DeleteOrigin(const std::string& origin_identifier, 383 bool force) { 384 if (!LazyInit()) 385 return false; 386 387 // Check if any database in this origin is opened by any renderer. 388 if (database_connections_.IsOriginUsed(origin_identifier) && !force) 389 return false; 390 391 int64 deleted_size = 0; 392 if (quota_manager_proxy_.get()) { 393 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); 394 if (origin_info) 395 deleted_size = origin_info->TotalSize(); 396 } 397 398 origins_info_map_.erase(origin_identifier); 399 base::FilePath origin_dir = db_dir_.AppendASCII(origin_identifier); 400 401 // Create a temporary directory to move possibly still existing databases to, 402 // as we can't delete the origin directory on windows if it contains opened 403 // files. 404 base::FilePath new_origin_dir; 405 base::CreateTemporaryDirInDir(db_dir_, 406 kTemporaryDirectoryPrefix, 407 &new_origin_dir); 408 base::FileEnumerator databases( 409 origin_dir, 410 false, 411 base::FileEnumerator::FILES); 412 for (base::FilePath database = databases.Next(); !database.empty(); 413 database = databases.Next()) { 414 base::FilePath new_file = new_origin_dir.Append(database.BaseName()); 415 base::Move(database, new_file); 416 } 417 base::DeleteFile(origin_dir, true); 418 base::DeleteFile(new_origin_dir, true); // might fail on windows. 419 420 databases_table_->DeleteOriginIdentifier(origin_identifier); 421 422 if (quota_manager_proxy_.get() && deleted_size) { 423 quota_manager_proxy_->NotifyStorageModified( 424 quota::QuotaClient::kDatabase, 425 webkit_database::GetOriginFromIdentifier(origin_identifier), 426 quota::kStorageTypeTemporary, 427 -deleted_size); 428 } 429 430 return true; 431 } 432 433 bool DatabaseTracker::IsDatabaseScheduledForDeletion( 434 const std::string& origin_identifier, 435 const base::string16& database_name) { 436 DatabaseSet::iterator it = dbs_to_be_deleted_.find(origin_identifier); 437 if (it == dbs_to_be_deleted_.end()) 438 return false; 439 440 std::set<base::string16>& databases = it->second; 441 return (databases.find(database_name) != databases.end()); 442 } 443 444 bool DatabaseTracker::LazyInit() { 445 if (!is_initialized_ && !shutting_down_) { 446 DCHECK(!db_->is_open()); 447 DCHECK(!databases_table_.get()); 448 DCHECK(!meta_table_.get()); 449 450 // If there are left-over directories from failed deletion attempts, clean 451 // them up. 452 if (base::DirectoryExists(db_dir_)) { 453 base::FileEnumerator directories( 454 db_dir_, 455 false, 456 base::FileEnumerator::DIRECTORIES, 457 kTemporaryDirectoryPattern); 458 for (base::FilePath directory = directories.Next(); !directory.empty(); 459 directory = directories.Next()) { 460 base::DeleteFile(directory, true); 461 } 462 } 463 464 // If the tracker database exists, but it's corrupt or doesn't 465 // have a meta table, delete the database directory. 466 const base::FilePath kTrackerDatabaseFullPath = 467 db_dir_.Append(base::FilePath(kTrackerDatabaseFileName)); 468 if (base::DirectoryExists(db_dir_) && 469 base::PathExists(kTrackerDatabaseFullPath) && 470 (!db_->Open(kTrackerDatabaseFullPath) || 471 !sql::MetaTable::DoesTableExist(db_.get()))) { 472 db_->Close(); 473 if (!base::DeleteFile(db_dir_, true)) 474 return false; 475 } 476 477 db_->set_histogram_tag("DatabaseTracker"); 478 479 databases_table_.reset(new DatabasesTable(db_.get())); 480 meta_table_.reset(new sql::MetaTable()); 481 482 is_initialized_ = 483 base::CreateDirectory(db_dir_) && 484 (db_->is_open() || 485 (is_incognito_ ? db_->OpenInMemory() : 486 db_->Open(kTrackerDatabaseFullPath))) && 487 UpgradeToCurrentVersion(); 488 if (!is_initialized_) { 489 databases_table_.reset(NULL); 490 meta_table_.reset(NULL); 491 db_->Close(); 492 } 493 } 494 return is_initialized_; 495 } 496 497 bool DatabaseTracker::UpgradeToCurrentVersion() { 498 sql::Transaction transaction(db_.get()); 499 if (!transaction.Begin() || 500 !meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion) || 501 (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) || 502 !databases_table_->Init()) 503 return false; 504 505 if (meta_table_->GetVersionNumber() < kCurrentVersion) 506 meta_table_->SetVersionNumber(kCurrentVersion); 507 508 return transaction.Commit(); 509 } 510 511 void DatabaseTracker::InsertOrUpdateDatabaseDetails( 512 const std::string& origin_identifier, 513 const base::string16& database_name, 514 const base::string16& database_description, 515 int64 estimated_size) { 516 DatabaseDetails details; 517 if (!databases_table_->GetDatabaseDetails( 518 origin_identifier, database_name, &details)) { 519 details.origin_identifier = origin_identifier; 520 details.database_name = database_name; 521 details.description = database_description; 522 details.estimated_size = estimated_size; 523 databases_table_->InsertDatabaseDetails(details); 524 } else if ((details.description != database_description) || 525 (details.estimated_size != estimated_size)) { 526 details.description = database_description; 527 details.estimated_size = estimated_size; 528 databases_table_->UpdateDatabaseDetails(details); 529 } 530 } 531 532 void DatabaseTracker::ClearAllCachedOriginInfo() { 533 origins_info_map_.clear(); 534 } 535 536 DatabaseTracker::CachedOriginInfo* DatabaseTracker::MaybeGetCachedOriginInfo( 537 const std::string& origin_identifier, bool create_if_needed) { 538 if (!LazyInit()) 539 return NULL; 540 541 // Populate the cache with data for this origin if needed. 542 if (origins_info_map_.find(origin_identifier) == origins_info_map_.end()) { 543 if (!create_if_needed) 544 return NULL; 545 546 std::vector<DatabaseDetails> details; 547 if (!databases_table_->GetAllDatabaseDetailsForOriginIdentifier( 548 origin_identifier, &details)) { 549 return NULL; 550 } 551 552 CachedOriginInfo& origin_info = origins_info_map_[origin_identifier]; 553 origin_info.SetOriginIdentifier(origin_identifier); 554 for (std::vector<DatabaseDetails>::const_iterator it = details.begin(); 555 it != details.end(); it++) { 556 int64 db_file_size; 557 if (database_connections_.IsDatabaseOpened( 558 origin_identifier, it->database_name)) { 559 db_file_size = database_connections_.GetOpenDatabaseSize( 560 origin_identifier, it->database_name); 561 } else { 562 db_file_size = GetDBFileSize(origin_identifier, it->database_name); 563 } 564 origin_info.SetDatabaseSize(it->database_name, db_file_size); 565 origin_info.SetDatabaseDescription(it->database_name, it->description); 566 } 567 } 568 569 return &origins_info_map_[origin_identifier]; 570 } 571 572 int64 DatabaseTracker::GetDBFileSize(const std::string& origin_identifier, 573 const base::string16& database_name) { 574 base::FilePath db_file_name = GetFullDBFilePath(origin_identifier, 575 database_name); 576 int64 db_file_size = 0; 577 if (!base::GetFileSize(db_file_name, &db_file_size)) 578 db_file_size = 0; 579 return db_file_size; 580 } 581 582 int64 DatabaseTracker::SeedOpenDatabaseInfo( 583 const std::string& origin_id, const base::string16& name, 584 const base::string16& description) { 585 DCHECK(database_connections_.IsDatabaseOpened(origin_id, name)); 586 int64 size = GetDBFileSize(origin_id, name); 587 database_connections_.SetOpenDatabaseSize(origin_id, name, size); 588 CachedOriginInfo* info = MaybeGetCachedOriginInfo(origin_id, false); 589 if (info) { 590 info->SetDatabaseSize(name, size); 591 info->SetDatabaseDescription(name, description); 592 } 593 return size; 594 } 595 596 int64 DatabaseTracker::UpdateOpenDatabaseInfoAndNotify( 597 const std::string& origin_id, const base::string16& name, 598 const base::string16* opt_description) { 599 DCHECK(database_connections_.IsDatabaseOpened(origin_id, name)); 600 int64 new_size = GetDBFileSize(origin_id, name); 601 int64 old_size = database_connections_.GetOpenDatabaseSize(origin_id, name); 602 CachedOriginInfo* info = MaybeGetCachedOriginInfo(origin_id, false); 603 if (info && opt_description) 604 info->SetDatabaseDescription(name, *opt_description); 605 if (old_size != new_size) { 606 database_connections_.SetOpenDatabaseSize(origin_id, name, new_size); 607 if (info) 608 info->SetDatabaseSize(name, new_size); 609 if (quota_manager_proxy_.get()) 610 quota_manager_proxy_->NotifyStorageModified( 611 quota::QuotaClient::kDatabase, 612 webkit_database::GetOriginFromIdentifier(origin_id), 613 quota::kStorageTypeTemporary, 614 new_size - old_size); 615 FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseSizeChanged( 616 origin_id, name, new_size)); 617 } 618 return new_size; 619 } 620 621 void DatabaseTracker::ScheduleDatabaseForDeletion( 622 const std::string& origin_identifier, 623 const base::string16& database_name) { 624 DCHECK(database_connections_.IsDatabaseOpened(origin_identifier, 625 database_name)); 626 dbs_to_be_deleted_[origin_identifier].insert(database_name); 627 FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseScheduledForDeletion( 628 origin_identifier, database_name)); 629 } 630 631 void DatabaseTracker::ScheduleDatabasesForDeletion( 632 const DatabaseSet& databases, 633 const net::CompletionCallback& callback) { 634 DCHECK(!databases.empty()); 635 636 if (!callback.is_null()) 637 deletion_callbacks_.push_back(std::make_pair(callback, databases)); 638 for (DatabaseSet::const_iterator ori = databases.begin(); 639 ori != databases.end(); ++ori) { 640 for (std::set<base::string16>::const_iterator db = ori->second.begin(); 641 db != ori->second.end(); ++db) 642 ScheduleDatabaseForDeletion(ori->first, *db); 643 } 644 } 645 646 int DatabaseTracker::DeleteDatabase(const std::string& origin_identifier, 647 const base::string16& database_name, 648 const net::CompletionCallback& callback) { 649 if (!LazyInit()) 650 return net::ERR_FAILED; 651 652 if (database_connections_.IsDatabaseOpened(origin_identifier, 653 database_name)) { 654 if (!callback.is_null()) { 655 DatabaseSet set; 656 set[origin_identifier].insert(database_name); 657 deletion_callbacks_.push_back(std::make_pair(callback, set)); 658 } 659 ScheduleDatabaseForDeletion(origin_identifier, database_name); 660 return net::ERR_IO_PENDING; 661 } 662 DeleteClosedDatabase(origin_identifier, database_name); 663 return net::OK; 664 } 665 666 int DatabaseTracker::DeleteDataModifiedSince( 667 const base::Time& cutoff, 668 const net::CompletionCallback& callback) { 669 if (!LazyInit()) 670 return net::ERR_FAILED; 671 672 DatabaseSet to_be_deleted; 673 674 std::vector<std::string> origins_identifiers; 675 if (!databases_table_->GetAllOriginIdentifiers(&origins_identifiers)) 676 return net::ERR_FAILED; 677 int rv = net::OK; 678 for (std::vector<std::string>::const_iterator ori = 679 origins_identifiers.begin(); 680 ori != origins_identifiers.end(); ++ori) { 681 if (special_storage_policy_.get() && 682 special_storage_policy_->IsStorageProtected( 683 webkit_database::GetOriginFromIdentifier(*ori))) { 684 continue; 685 } 686 687 std::vector<DatabaseDetails> details; 688 if (!databases_table_-> 689 GetAllDatabaseDetailsForOriginIdentifier(*ori, &details)) 690 rv = net::ERR_FAILED; 691 for (std::vector<DatabaseDetails>::const_iterator db = details.begin(); 692 db != details.end(); ++db) { 693 base::FilePath db_file = GetFullDBFilePath(*ori, db->database_name); 694 base::PlatformFileInfo file_info; 695 base::GetFileInfo(db_file, &file_info); 696 if (file_info.last_modified < cutoff) 697 continue; 698 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); 704 } 705 } 706 707 if (rv != net::OK) 708 return rv; 709 710 if (!to_be_deleted.empty()) { 711 ScheduleDatabasesForDeletion(to_be_deleted, callback); 712 return net::ERR_IO_PENDING; 713 } 714 return net::OK; 715 } 716 717 int DatabaseTracker::DeleteDataForOrigin( 718 const std::string& origin, const net::CompletionCallback& callback) { 719 if (!LazyInit()) 720 return net::ERR_FAILED; 721 722 DatabaseSet to_be_deleted; 723 724 std::vector<DatabaseDetails> details; 725 if (!databases_table_-> 726 GetAllDatabaseDetailsForOriginIdentifier(origin, &details)) 727 return net::ERR_FAILED; 728 for (std::vector<DatabaseDetails>::const_iterator db = details.begin(); 729 db != details.end(); ++db) { 730 // Check if the database is opened by any renderer. 731 if (database_connections_.IsDatabaseOpened(origin, db->database_name)) 732 to_be_deleted[origin].insert(db->database_name); 733 else 734 DeleteClosedDatabase(origin, db->database_name); 735 } 736 737 if (!to_be_deleted.empty()) { 738 ScheduleDatabasesForDeletion(to_be_deleted, callback); 739 return net::ERR_IO_PENDING; 740 } 741 return net::OK; 742 } 743 744 void DatabaseTracker::GetIncognitoFileHandle( 745 const base::string16& vfs_file_name, 746 base::PlatformFile* file_handle) const { 747 DCHECK(is_incognito_); 748 FileHandlesMap::const_iterator it = 749 incognito_file_handles_.find(vfs_file_name); 750 if (it != incognito_file_handles_.end()) 751 *file_handle = it->second; 752 else 753 *file_handle = base::kInvalidPlatformFileValue; 754 } 755 756 void DatabaseTracker::SaveIncognitoFileHandle( 757 const base::string16& vfs_file_name, 758 const base::PlatformFile& file_handle) { 759 DCHECK(is_incognito_); 760 DCHECK(incognito_file_handles_.find(vfs_file_name) == 761 incognito_file_handles_.end()); 762 if (file_handle != base::kInvalidPlatformFileValue) 763 incognito_file_handles_[vfs_file_name] = file_handle; 764 } 765 766 bool DatabaseTracker::CloseIncognitoFileHandle( 767 const base::string16& vfs_file_name) { 768 DCHECK(is_incognito_); 769 DCHECK(incognito_file_handles_.find(vfs_file_name) != 770 incognito_file_handles_.end()); 771 772 bool handle_closed = false; 773 FileHandlesMap::iterator it = incognito_file_handles_.find(vfs_file_name); 774 if (it != incognito_file_handles_.end()) { 775 handle_closed = base::ClosePlatformFile(it->second); 776 if (handle_closed) 777 incognito_file_handles_.erase(it); 778 } 779 return handle_closed; 780 } 781 782 bool DatabaseTracker::HasSavedIncognitoFileHandle( 783 const base::string16& vfs_file_name) const { 784 return (incognito_file_handles_.find(vfs_file_name) != 785 incognito_file_handles_.end()); 786 } 787 788 void DatabaseTracker::DeleteIncognitoDBDirectory() { 789 is_initialized_ = false; 790 791 for (FileHandlesMap::iterator it = incognito_file_handles_.begin(); 792 it != incognito_file_handles_.end(); it++) 793 base::ClosePlatformFile(it->second); 794 795 base::FilePath incognito_db_dir = 796 profile_path_.Append(kIncognitoDatabaseDirectoryName); 797 if (base::DirectoryExists(incognito_db_dir)) 798 base::DeleteFile(incognito_db_dir, true); 799 } 800 801 void DatabaseTracker::ClearSessionOnlyOrigins() { 802 bool has_session_only_databases = 803 special_storage_policy_.get() && 804 special_storage_policy_->HasSessionOnlyOrigins(); 805 806 // Clearing only session-only databases, and there are none. 807 if (!has_session_only_databases) 808 return; 809 810 if (!LazyInit()) 811 return; 812 813 std::vector<std::string> origin_identifiers; 814 GetAllOriginIdentifiers(&origin_identifiers); 815 816 for (std::vector<std::string>::iterator origin = 817 origin_identifiers.begin(); 818 origin != origin_identifiers.end(); ++origin) { 819 GURL origin_url = webkit_database::GetOriginFromIdentifier(*origin); 820 if (!special_storage_policy_->IsStorageSessionOnly(origin_url)) 821 continue; 822 if (special_storage_policy_->IsStorageProtected(origin_url)) 823 continue; 824 webkit_database::OriginInfo origin_info; 825 std::vector<base::string16> databases; 826 GetOriginInfo(*origin, &origin_info); 827 origin_info.GetAllDatabaseNames(&databases); 828 829 for (std::vector<base::string16>::iterator database = databases.begin(); 830 database != databases.end(); ++database) { 831 base::PlatformFile file_handle = base::CreatePlatformFile( 832 GetFullDBFilePath(*origin, *database), 833 base::PLATFORM_FILE_OPEN_ALWAYS | 834 base::PLATFORM_FILE_SHARE_DELETE | 835 base::PLATFORM_FILE_DELETE_ON_CLOSE | 836 base::PLATFORM_FILE_READ, 837 NULL, NULL); 838 base::ClosePlatformFile(file_handle); 839 } 840 DeleteOrigin(*origin, true); 841 } 842 } 843 844 845 void DatabaseTracker::Shutdown() { 846 DCHECK(db_tracker_thread_.get()); 847 DCHECK(db_tracker_thread_->BelongsToCurrentThread()); 848 if (shutting_down_) { 849 NOTREACHED(); 850 return; 851 } 852 shutting_down_ = true; 853 if (is_incognito_) 854 DeleteIncognitoDBDirectory(); 855 else if (!force_keep_session_state_) 856 ClearSessionOnlyOrigins(); 857 CloseTrackerDatabaseAndClearCaches(); 858 } 859 860 void DatabaseTracker::SetForceKeepSessionState() { 861 DCHECK(db_tracker_thread_.get()); 862 if (!db_tracker_thread_->BelongsToCurrentThread()) { 863 db_tracker_thread_->PostTask( 864 FROM_HERE, 865 base::Bind(&DatabaseTracker::SetForceKeepSessionState, this)); 866 return; 867 } 868 force_keep_session_state_ = true; 869 } 870 871 } // namespace webkit_database 872