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
OriginInfo()46 OriginInfo::OriginInfo()
47 : total_size_(0) {}
48
OriginInfo(const OriginInfo & origin_info)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
~OriginInfo()54 OriginInfo::~OriginInfo() {}
55
GetAllDatabaseNames(std::vector<base::string16> * databases) const56 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
GetDatabaseSize(const base::string16 & database_name) const64 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
GetDatabaseDescription(const base::string16 & database_name) const71 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
OriginInfo(const std::string & origin_identifier,int64 total_size)79 OriginInfo::OriginInfo(const std::string& origin_identifier, int64 total_size)
80 : origin_identifier_(origin_identifier), total_size_(total_size) {}
81
DatabaseTracker(const base::FilePath & profile_path,bool is_incognito,storage::SpecialStoragePolicy * special_storage_policy,storage::QuotaManagerProxy * quota_manager_proxy,base::MessageLoopProxy * db_tracker_thread)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
~DatabaseTracker()107 DatabaseTracker::~DatabaseTracker() {
108 DCHECK(dbs_to_be_deleted_.empty());
109 DCHECK(deletion_callbacks_.empty());
110 }
111
DatabaseOpened(const std::string & origin_identifier,const base::string16 & database_name,const base::string16 & database_description,int64 estimated_size,int64 * database_size)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
DatabaseModified(const std::string & origin_identifier,const base::string16 & database_name)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
DatabaseClosed(const std::string & origin_identifier,const base::string16 & database_name)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
HandleSqliteError(const std::string & origin_identifier,const base::string16 & database_name,int error)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
CloseDatabases(const DatabaseConnections & connections)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
DeleteDatabaseIfNeeded(const std::string & origin_identifier,const base::string16 & database_name)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
AddObserver(Observer * observer)246 void DatabaseTracker::AddObserver(Observer* observer) {
247 observers_.AddObserver(observer);
248 }
249
RemoveObserver(Observer * observer)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
CloseTrackerDatabaseAndClearCaches()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
GetOriginDirectory(const std::string & origin_identifier)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
GetFullDBFilePath(const std::string & origin_identifier,const base::string16 & database_name)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
GetOriginInfo(const std::string & origin_identifier,OriginInfo * info)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
GetAllOriginIdentifiers(std::vector<std::string> * origin_identifiers)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
GetAllOriginsInfo(std::vector<OriginInfo> * origins_info)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
DeleteClosedDatabase(const std::string & origin_identifier,const base::string16 & database_name)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
DeleteOrigin(const std::string & origin_identifier,bool force)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
IsDatabaseScheduledForDeletion(const std::string & origin_identifier,const base::string16 & database_name)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
LazyInit()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
UpgradeToCurrentVersion()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
InsertOrUpdateDatabaseDetails(const std::string & origin_identifier,const base::string16 & database_name,const base::string16 & database_description,int64 estimated_size)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
ClearAllCachedOriginInfo()532 void DatabaseTracker::ClearAllCachedOriginInfo() {
533 origins_info_map_.clear();
534 }
535
MaybeGetCachedOriginInfo(const std::string & origin_identifier,bool create_if_needed)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
GetDBFileSize(const std::string & origin_identifier,const base::string16 & database_name)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
SeedOpenDatabaseInfo(const std::string & origin_id,const base::string16 & name,const base::string16 & description)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
UpdateOpenDatabaseInfoAndNotify(const std::string & origin_id,const base::string16 & name,const base::string16 * opt_description)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
ScheduleDatabaseForDeletion(const std::string & origin_identifier,const base::string16 & database_name)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
ScheduleDatabasesForDeletion(const DatabaseSet & databases,const net::CompletionCallback & callback)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
DeleteDatabase(const std::string & origin_identifier,const base::string16 & database_name,const net::CompletionCallback & callback)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
DeleteDataModifiedSince(const base::Time & cutoff,const net::CompletionCallback & callback)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
DeleteDataForOrigin(const std::string & origin,const net::CompletionCallback & callback)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
GetIncognitoFile(const base::string16 & vfs_file_name) const744 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
SaveIncognitoFile(const base::string16 & vfs_file_name,base::File file)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
CloseIncognitoFileHandle(const base::string16 & vfs_file_name)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
HasSavedIncognitoFileHandle(const base::string16 & vfs_file_name) const782 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
DeleteIncognitoDBDirectory()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
ClearSessionOnlyOrigins()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
Shutdown()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
SetForceKeepSessionState()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