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 "storage/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/files/file.h" 13 #include "base/files/file_enumerator.h" 14 #include "base/files/file_util.h" 15 #include "base/message_loop/message_loop_proxy.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 "storage/browser/database/database_quota_client.h" 23 #include "storage/browser/database/database_util.h" 24 #include "storage/browser/database/databases_table.h" 25 #include "storage/browser/quota/quota_manager_proxy.h" 26 #include "storage/browser/quota/special_storage_policy.h" 27 #include "storage/common/database/database_identifier.h" 28 #include "third_party/sqlite/sqlite3.h" 29 30 namespace storage { 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 storage::SpecialStoragePolicy* special_storage_policy, 86 storage::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 storage::QuotaClient::kDatabase, 125 storage::GetOriginFromIdentifier(origin_identifier), 126 storage::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 storage::QuotaClient::kDatabase, 160 storage::GetOriginFromIdentifier(origin_identifier), 161 storage::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 storage::QuotaClient::kDatabase, 365 storage::GetOriginFromIdentifier(origin_identifier), 366 storage::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 storage::QuotaClient::kDatabase, 425 storage::GetOriginFromIdentifier(origin_identifier), 426 storage::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 storage::QuotaClient::kDatabase, 612 storage::GetOriginFromIdentifier(origin_id), 613 storage::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 storage::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::File::Info 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 const base::File* DatabaseTracker::GetIncognitoFile( 745 const base::string16& vfs_file_name) const { 746 DCHECK(is_incognito_); 747 FileHandlesMap::const_iterator it = 748 incognito_file_handles_.find(vfs_file_name); 749 if (it != incognito_file_handles_.end()) 750 return it->second; 751 752 return NULL; 753 } 754 755 const base::File* DatabaseTracker::SaveIncognitoFile( 756 const base::string16& vfs_file_name, 757 base::File file) { 758 DCHECK(is_incognito_); 759 if (!file.IsValid()) 760 return NULL; 761 762 base::File* to_insert = new base::File(file.Pass()); 763 std::pair<FileHandlesMap::iterator, bool> rv = 764 incognito_file_handles_.insert(std::make_pair(vfs_file_name, to_insert)); 765 DCHECK(rv.second); 766 return rv.first->second; 767 } 768 769 void DatabaseTracker::CloseIncognitoFileHandle( 770 const base::string16& vfs_file_name) { 771 DCHECK(is_incognito_); 772 DCHECK(incognito_file_handles_.find(vfs_file_name) != 773 incognito_file_handles_.end()); 774 775 FileHandlesMap::iterator it = incognito_file_handles_.find(vfs_file_name); 776 if (it != incognito_file_handles_.end()) { 777 delete it->second; 778 incognito_file_handles_.erase(it); 779 } 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 delete it->second; 794 } 795 796 base::FilePath incognito_db_dir = 797 profile_path_.Append(kIncognitoDatabaseDirectoryName); 798 if (base::DirectoryExists(incognito_db_dir)) 799 base::DeleteFile(incognito_db_dir, true); 800 } 801 802 void DatabaseTracker::ClearSessionOnlyOrigins() { 803 bool has_session_only_databases = 804 special_storage_policy_.get() && 805 special_storage_policy_->HasSessionOnlyOrigins(); 806 807 // Clearing only session-only databases, and there are none. 808 if (!has_session_only_databases) 809 return; 810 811 if (!LazyInit()) 812 return; 813 814 std::vector<std::string> origin_identifiers; 815 GetAllOriginIdentifiers(&origin_identifiers); 816 817 for (std::vector<std::string>::iterator origin = 818 origin_identifiers.begin(); 819 origin != origin_identifiers.end(); ++origin) { 820 GURL origin_url = storage::GetOriginFromIdentifier(*origin); 821 if (!special_storage_policy_->IsStorageSessionOnly(origin_url)) 822 continue; 823 if (special_storage_policy_->IsStorageProtected(origin_url)) 824 continue; 825 storage::OriginInfo origin_info; 826 std::vector<base::string16> databases; 827 GetOriginInfo(*origin, &origin_info); 828 origin_info.GetAllDatabaseNames(&databases); 829 830 for (std::vector<base::string16>::iterator database = databases.begin(); 831 database != databases.end(); ++database) { 832 base::File file(GetFullDBFilePath(*origin, *database), 833 base::File::FLAG_OPEN_ALWAYS | 834 base::File::FLAG_SHARE_DELETE | 835 base::File::FLAG_DELETE_ON_CLOSE | 836 base::File::FLAG_READ); 837 } 838 DeleteOrigin(*origin, true); 839 } 840 } 841 842 843 void DatabaseTracker::Shutdown() { 844 DCHECK(db_tracker_thread_.get()); 845 DCHECK(db_tracker_thread_->BelongsToCurrentThread()); 846 if (shutting_down_) { 847 NOTREACHED(); 848 return; 849 } 850 shutting_down_ = true; 851 if (is_incognito_) 852 DeleteIncognitoDBDirectory(); 853 else if (!force_keep_session_state_) 854 ClearSessionOnlyOrigins(); 855 CloseTrackerDatabaseAndClearCaches(); 856 } 857 858 void DatabaseTracker::SetForceKeepSessionState() { 859 DCHECK(db_tracker_thread_.get()); 860 if (!db_tracker_thread_->BelongsToCurrentThread()) { 861 db_tracker_thread_->PostTask( 862 FROM_HERE, 863 base::Bind(&DatabaseTracker::SetForceKeepSessionState, this)); 864 return; 865 } 866 force_keep_session_state_ = true; 867 } 868 869 } // namespace storage 870