1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "storage/browser/database/database_tracker.h"
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/files/file_util.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "net/base/net_errors.h"
17 #include "sql/connection.h"
18 #include "sql/meta_table.h"
19 #include "sql/transaction.h"
20 #include "storage/browser/database/database_quota_client.h"
21 #include "storage/browser/database/database_util.h"
22 #include "storage/browser/database/databases_table.h"
23 #include "storage/browser/quota/quota_manager_proxy.h"
24 #include "storage/browser/quota/special_storage_policy.h"
25 #include "storage/common/database/database_identifier.h"
26 #include "third_party/sqlite/sqlite3.h"
30 const base::FilePath::CharType kDatabaseDirectoryName
[] =
31 FILE_PATH_LITERAL("databases");
32 const base::FilePath::CharType kIncognitoDatabaseDirectoryName
[] =
33 FILE_PATH_LITERAL("databases-incognito");
34 const base::FilePath::CharType kTrackerDatabaseFileName
[] =
35 FILE_PATH_LITERAL("Databases.db");
36 static const int kCurrentVersion
= 2;
37 static const int kCompatibleVersion
= 1;
39 const base::FilePath::CharType kTemporaryDirectoryPrefix
[] =
40 FILE_PATH_LITERAL("DeleteMe");
41 const base::FilePath::CharType kTemporaryDirectoryPattern
[] =
42 FILE_PATH_LITERAL("DeleteMe*");
44 OriginInfo::OriginInfo()
47 OriginInfo::OriginInfo(const OriginInfo
& origin_info
)
48 : origin_identifier_(origin_info
.origin_identifier_
),
49 total_size_(origin_info
.total_size_
),
50 database_info_(origin_info
.database_info_
) {}
52 OriginInfo::~OriginInfo() {}
54 void OriginInfo::GetAllDatabaseNames(
55 std::vector
<base::string16
>* databases
) const {
56 for (DatabaseInfoMap::const_iterator it
= database_info_
.begin();
57 it
!= database_info_
.end(); it
++) {
58 databases
->push_back(it
->first
);
62 int64
OriginInfo::GetDatabaseSize(const base::string16
& database_name
) const {
63 DatabaseInfoMap::const_iterator it
= database_info_
.find(database_name
);
64 if (it
!= database_info_
.end())
65 return it
->second
.first
;
69 base::string16
OriginInfo::GetDatabaseDescription(
70 const base::string16
& database_name
) const {
71 DatabaseInfoMap::const_iterator it
= database_info_
.find(database_name
);
72 if (it
!= database_info_
.end())
73 return it
->second
.second
;
74 return base::string16();
77 OriginInfo::OriginInfo(const std::string
& origin_identifier
, int64 total_size
)
78 : origin_identifier_(origin_identifier
), total_size_(total_size
) {}
80 DatabaseTracker::DatabaseTracker(
81 const base::FilePath
& profile_path
,
83 storage::SpecialStoragePolicy
* special_storage_policy
,
84 storage::QuotaManagerProxy
* quota_manager_proxy
,
85 base::SingleThreadTaskRunner
* db_tracker_thread
)
86 : is_initialized_(false),
87 is_incognito_(is_incognito
),
88 force_keep_session_state_(false),
89 shutting_down_(false),
90 profile_path_(profile_path
),
92 ? profile_path_
.Append(kIncognitoDatabaseDirectoryName
)
93 : profile_path_
.Append(kDatabaseDirectoryName
)),
94 db_(new sql::Connection()),
95 special_storage_policy_(special_storage_policy
),
96 quota_manager_proxy_(quota_manager_proxy
),
97 db_tracker_thread_(db_tracker_thread
),
98 incognito_origin_directories_generator_(0) {
99 if (quota_manager_proxy
) {
100 quota_manager_proxy
->RegisterClient(
101 new DatabaseQuotaClient(db_tracker_thread
, this));
105 DatabaseTracker::~DatabaseTracker() {
106 DCHECK(dbs_to_be_deleted_
.empty());
107 DCHECK(deletion_callbacks_
.empty());
110 void DatabaseTracker::DatabaseOpened(const std::string
& origin_identifier
,
111 const base::string16
& database_name
,
112 const base::string16
& database_description
,
113 int64 estimated_size
,
114 int64
* database_size
) {
115 if (shutting_down_
|| !LazyInit()) {
120 if (quota_manager_proxy_
.get())
121 quota_manager_proxy_
->NotifyStorageAccessed(
122 storage::QuotaClient::kDatabase
,
123 storage::GetOriginFromIdentifier(origin_identifier
),
124 storage::kStorageTypeTemporary
);
126 InsertOrUpdateDatabaseDetails(origin_identifier
, database_name
,
127 database_description
, estimated_size
);
128 if (database_connections_
.AddConnection(origin_identifier
, database_name
)) {
129 *database_size
= SeedOpenDatabaseInfo(origin_identifier
,
131 database_description
);
134 *database_size
= UpdateOpenDatabaseInfoAndNotify(origin_identifier
,
136 &database_description
);
139 void DatabaseTracker::DatabaseModified(const std::string
& origin_identifier
,
140 const base::string16
& database_name
) {
143 UpdateOpenDatabaseSizeAndNotify(origin_identifier
, database_name
);
146 void DatabaseTracker::DatabaseClosed(const std::string
& origin_identifier
,
147 const base::string16
& database_name
) {
148 if (database_connections_
.IsEmpty()) {
149 DCHECK(!is_initialized_
);
153 // We call NotifiyStorageAccessed when a db is opened and also when
154 // closed because we don't call it for read while open.
155 if (quota_manager_proxy_
.get())
156 quota_manager_proxy_
->NotifyStorageAccessed(
157 storage::QuotaClient::kDatabase
,
158 storage::GetOriginFromIdentifier(origin_identifier
),
159 storage::kStorageTypeTemporary
);
161 UpdateOpenDatabaseSizeAndNotify(origin_identifier
, database_name
);
162 if (database_connections_
.RemoveConnection(origin_identifier
, database_name
))
163 DeleteDatabaseIfNeeded(origin_identifier
, database_name
);
166 void DatabaseTracker::HandleSqliteError(
167 const std::string
& origin_identifier
,
168 const base::string16
& database_name
,
170 // We only handle errors that indicate corruption and we
171 // do so with a heavy hand, we delete it. Any renderers/workers
172 // with this database open will receive a message to close it
173 // immediately, once all have closed, the files will be deleted.
174 // In the interim, all attempts to open a new connection to that
175 // database will fail.
176 // Note: the client-side filters out all but these two errors as
177 // a small optimization, see WebDatabaseObserverImpl::HandleSqliteError.
178 if (error
== SQLITE_CORRUPT
|| error
== SQLITE_NOTADB
) {
179 DeleteDatabase(origin_identifier
, database_name
,
180 net::CompletionCallback());
184 void DatabaseTracker::CloseDatabases(const DatabaseConnections
& connections
) {
185 if (database_connections_
.IsEmpty()) {
186 DCHECK(!is_initialized_
|| connections
.IsEmpty());
190 // When being closed by this route, there's a chance that
191 // the tracker missed some DatabseModified calls. This method is used
192 // when a renderer crashes to cleanup its open resources.
193 // We need to examine what we have in connections for the
194 // size of each open databases and notify any differences between the
195 // actual file sizes now.
196 std::vector
<std::pair
<std::string
, base::string16
> > open_dbs
;
197 connections
.ListConnections(&open_dbs
);
198 for (std::vector
<std::pair
<std::string
, base::string16
> >::iterator it
=
199 open_dbs
.begin(); it
!= open_dbs
.end(); ++it
)
200 UpdateOpenDatabaseSizeAndNotify(it
->first
, it
->second
);
202 std::vector
<std::pair
<std::string
, base::string16
> > closed_dbs
;
203 database_connections_
.RemoveConnections(connections
, &closed_dbs
);
204 for (std::vector
<std::pair
<std::string
, base::string16
> >::iterator it
=
205 closed_dbs
.begin(); it
!= closed_dbs
.end(); ++it
) {
206 DeleteDatabaseIfNeeded(it
->first
, it
->second
);
210 void DatabaseTracker::DeleteDatabaseIfNeeded(
211 const std::string
& origin_identifier
,
212 const base::string16
& database_name
) {
213 DCHECK(!database_connections_
.IsDatabaseOpened(origin_identifier
,
215 if (IsDatabaseScheduledForDeletion(origin_identifier
, database_name
)) {
216 DeleteClosedDatabase(origin_identifier
, database_name
);
217 dbs_to_be_deleted_
[origin_identifier
].erase(database_name
);
218 if (dbs_to_be_deleted_
[origin_identifier
].empty())
219 dbs_to_be_deleted_
.erase(origin_identifier
);
221 PendingDeletionCallbacks::iterator callback
= deletion_callbacks_
.begin();
222 while (callback
!= deletion_callbacks_
.end()) {
223 DatabaseSet::iterator found_origin
=
224 callback
->second
.find(origin_identifier
);
225 if (found_origin
!= callback
->second
.end()) {
226 std::set
<base::string16
>& databases
= found_origin
->second
;
227 databases
.erase(database_name
);
228 if (databases
.empty()) {
229 callback
->second
.erase(found_origin
);
230 if (callback
->second
.empty()) {
231 net::CompletionCallback cb
= callback
->first
;
233 callback
= deletion_callbacks_
.erase(callback
);
244 void DatabaseTracker::AddObserver(Observer
* observer
) {
245 observers_
.AddObserver(observer
);
248 void DatabaseTracker::RemoveObserver(Observer
* observer
) {
249 // When we remove a listener, we do not know which cached information
250 // is still needed and which information can be discarded. So we just
251 // clear all caches and re-populate them as needed.
252 observers_
.RemoveObserver(observer
);
253 ClearAllCachedOriginInfo();
256 void DatabaseTracker::CloseTrackerDatabaseAndClearCaches() {
257 ClearAllCachedOriginInfo();
259 if (!is_incognito_
) {
260 meta_table_
.reset(NULL
);
261 databases_table_
.reset(NULL
);
263 is_initialized_
= false;
267 base::string16
DatabaseTracker::GetOriginDirectory(
268 const std::string
& origin_identifier
) {
270 return base::UTF8ToUTF16(origin_identifier
);
272 OriginDirectoriesMap::const_iterator it
=
273 incognito_origin_directories_
.find(origin_identifier
);
274 if (it
!= incognito_origin_directories_
.end())
277 base::string16 origin_directory
=
278 base::IntToString16(incognito_origin_directories_generator_
++);
279 incognito_origin_directories_
[origin_identifier
] = origin_directory
;
280 return origin_directory
;
283 base::FilePath
DatabaseTracker::GetFullDBFilePath(
284 const std::string
& origin_identifier
,
285 const base::string16
& database_name
) {
286 DCHECK(!origin_identifier
.empty());
288 return base::FilePath();
290 int64 id
= databases_table_
->GetDatabaseID(origin_identifier
, database_name
);
292 return base::FilePath();
294 return db_dir_
.Append(base::FilePath::FromUTF16Unsafe(
295 GetOriginDirectory(origin_identifier
))).AppendASCII(
296 base::Int64ToString(id
));
299 bool DatabaseTracker::GetOriginInfo(const std::string
& origin_identifier
,
302 CachedOriginInfo
* cached_info
= GetCachedOriginInfo(origin_identifier
);
305 *info
= OriginInfo(*cached_info
);
309 bool DatabaseTracker::GetAllOriginIdentifiers(
310 std::vector
<std::string
>* origin_identifiers
) {
311 DCHECK(origin_identifiers
);
312 DCHECK(origin_identifiers
->empty());
315 return databases_table_
->GetAllOriginIdentifiers(origin_identifiers
);
318 bool DatabaseTracker::GetAllOriginsInfo(
319 std::vector
<OriginInfo
>* origins_info
) {
320 DCHECK(origins_info
);
321 DCHECK(origins_info
->empty());
323 std::vector
<std::string
> origins
;
324 if (!GetAllOriginIdentifiers(&origins
))
327 for (std::vector
<std::string
>::const_iterator it
= origins
.begin();
328 it
!= origins
.end(); it
++) {
329 CachedOriginInfo
* origin_info
= GetCachedOriginInfo(*it
);
331 // Restore 'origins_info' to its initial state.
332 origins_info
->clear();
335 origins_info
->push_back(OriginInfo(*origin_info
));
341 bool DatabaseTracker::DeleteClosedDatabase(
342 const std::string
& origin_identifier
,
343 const base::string16
& database_name
) {
347 // Check if the database is opened by any renderer.
348 if (database_connections_
.IsDatabaseOpened(origin_identifier
, database_name
))
351 int64 db_file_size
= quota_manager_proxy_
.get()
352 ? GetDBFileSize(origin_identifier
, database_name
)
355 // Try to delete the file on the hard drive.
356 base::FilePath db_file
= GetFullDBFilePath(origin_identifier
, database_name
);
357 if (!sql::Connection::Delete(db_file
))
360 if (quota_manager_proxy_
.get() && db_file_size
)
361 quota_manager_proxy_
->NotifyStorageModified(
362 storage::QuotaClient::kDatabase
,
363 storage::GetOriginFromIdentifier(origin_identifier
),
364 storage::kStorageTypeTemporary
,
367 // Clean up the main database and invalidate the cached record.
368 databases_table_
->DeleteDatabaseDetails(origin_identifier
, database_name
);
369 origins_info_map_
.erase(origin_identifier
);
371 std::vector
<DatabaseDetails
> details
;
372 if (databases_table_
->GetAllDatabaseDetailsForOriginIdentifier(
373 origin_identifier
, &details
) && details
.empty()) {
374 // Try to delete the origin in case this was the last database.
375 DeleteOrigin(origin_identifier
, false);
380 bool DatabaseTracker::DeleteOrigin(const std::string
& origin_identifier
,
385 // Check if any database in this origin is opened by any renderer.
386 if (database_connections_
.IsOriginUsed(origin_identifier
) && !force
)
389 int64 deleted_size
= 0;
390 if (quota_manager_proxy_
.get()) {
391 CachedOriginInfo
* origin_info
= GetCachedOriginInfo(origin_identifier
);
393 deleted_size
= origin_info
->TotalSize();
396 origins_info_map_
.erase(origin_identifier
);
397 base::FilePath origin_dir
= db_dir_
.AppendASCII(origin_identifier
);
399 // Create a temporary directory to move possibly still existing databases to,
400 // as we can't delete the origin directory on windows if it contains opened
402 base::FilePath new_origin_dir
;
403 base::CreateTemporaryDirInDir(db_dir_
,
404 kTemporaryDirectoryPrefix
,
406 base::FileEnumerator
databases(
409 base::FileEnumerator::FILES
);
410 for (base::FilePath database
= databases
.Next(); !database
.empty();
411 database
= databases
.Next()) {
412 base::FilePath new_file
= new_origin_dir
.Append(database
.BaseName());
413 base::Move(database
, new_file
);
415 base::DeleteFile(origin_dir
, true);
416 base::DeleteFile(new_origin_dir
, true); // might fail on windows.
418 databases_table_
->DeleteOriginIdentifier(origin_identifier
);
420 if (quota_manager_proxy_
.get() && deleted_size
) {
421 quota_manager_proxy_
->NotifyStorageModified(
422 storage::QuotaClient::kDatabase
,
423 storage::GetOriginFromIdentifier(origin_identifier
),
424 storage::kStorageTypeTemporary
,
431 bool DatabaseTracker::IsDatabaseScheduledForDeletion(
432 const std::string
& origin_identifier
,
433 const base::string16
& database_name
) {
434 DatabaseSet::iterator it
= dbs_to_be_deleted_
.find(origin_identifier
);
435 if (it
== dbs_to_be_deleted_
.end())
438 std::set
<base::string16
>& databases
= it
->second
;
439 return (databases
.find(database_name
) != databases
.end());
442 bool DatabaseTracker::LazyInit() {
443 if (!is_initialized_
&& !shutting_down_
) {
444 DCHECK(!db_
->is_open());
445 DCHECK(!databases_table_
.get());
446 DCHECK(!meta_table_
.get());
448 // If there are left-over directories from failed deletion attempts, clean
450 if (base::DirectoryExists(db_dir_
)) {
451 base::FileEnumerator
directories(
454 base::FileEnumerator::DIRECTORIES
,
455 kTemporaryDirectoryPattern
);
456 for (base::FilePath directory
= directories
.Next(); !directory
.empty();
457 directory
= directories
.Next()) {
458 base::DeleteFile(directory
, true);
462 db_
->set_histogram_tag("DatabaseTracker");
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()))) {
473 if (!base::DeleteFile(db_dir_
, true))
477 databases_table_
.reset(new DatabasesTable(db_
.get()));
478 meta_table_
.reset(new sql::MetaTable());
481 base::CreateDirectory(db_dir_
) &&
483 (is_incognito_
? db_
->OpenInMemory() :
484 db_
->Open(kTrackerDatabaseFullPath
))) &&
485 UpgradeToCurrentVersion();
486 if (!is_initialized_
) {
487 databases_table_
.reset(NULL
);
488 meta_table_
.reset(NULL
);
492 return is_initialized_
;
495 bool DatabaseTracker::UpgradeToCurrentVersion() {
496 sql::Transaction
transaction(db_
.get());
497 if (!transaction
.Begin() ||
498 !meta_table_
->Init(db_
.get(), kCurrentVersion
, kCompatibleVersion
) ||
499 (meta_table_
->GetCompatibleVersionNumber() > kCurrentVersion
) ||
500 !databases_table_
->Init())
503 if (meta_table_
->GetVersionNumber() < kCurrentVersion
)
504 meta_table_
->SetVersionNumber(kCurrentVersion
);
506 return transaction
.Commit();
509 void DatabaseTracker::InsertOrUpdateDatabaseDetails(
510 const std::string
& origin_identifier
,
511 const base::string16
& database_name
,
512 const base::string16
& database_description
,
513 int64 estimated_size
) {
514 DatabaseDetails details
;
515 if (!databases_table_
->GetDatabaseDetails(
516 origin_identifier
, database_name
, &details
)) {
517 details
.origin_identifier
= origin_identifier
;
518 details
.database_name
= database_name
;
519 details
.description
= database_description
;
520 details
.estimated_size
= estimated_size
;
521 databases_table_
->InsertDatabaseDetails(details
);
522 } else if ((details
.description
!= database_description
) ||
523 (details
.estimated_size
!= estimated_size
)) {
524 details
.description
= database_description
;
525 details
.estimated_size
= estimated_size
;
526 databases_table_
->UpdateDatabaseDetails(details
);
530 void DatabaseTracker::ClearAllCachedOriginInfo() {
531 origins_info_map_
.clear();
534 DatabaseTracker::CachedOriginInfo
* DatabaseTracker::MaybeGetCachedOriginInfo(
535 const std::string
& origin_identifier
, bool create_if_needed
) {
539 // Populate the cache with data for this origin if needed.
540 if (origins_info_map_
.find(origin_identifier
) == origins_info_map_
.end()) {
541 if (!create_if_needed
)
544 std::vector
<DatabaseDetails
> details
;
545 if (!databases_table_
->GetAllDatabaseDetailsForOriginIdentifier(
546 origin_identifier
, &details
)) {
550 CachedOriginInfo
& origin_info
= origins_info_map_
[origin_identifier
];
551 origin_info
.SetOriginIdentifier(origin_identifier
);
552 for (std::vector
<DatabaseDetails
>::const_iterator it
= details
.begin();
553 it
!= details
.end(); it
++) {
555 if (database_connections_
.IsDatabaseOpened(
556 origin_identifier
, it
->database_name
)) {
557 db_file_size
= database_connections_
.GetOpenDatabaseSize(
558 origin_identifier
, it
->database_name
);
560 db_file_size
= GetDBFileSize(origin_identifier
, it
->database_name
);
562 origin_info
.SetDatabaseSize(it
->database_name
, db_file_size
);
563 origin_info
.SetDatabaseDescription(it
->database_name
, it
->description
);
567 return &origins_info_map_
[origin_identifier
];
570 int64
DatabaseTracker::GetDBFileSize(const std::string
& origin_identifier
,
571 const base::string16
& database_name
) {
572 base::FilePath db_file_name
= GetFullDBFilePath(origin_identifier
,
574 int64 db_file_size
= 0;
575 if (!base::GetFileSize(db_file_name
, &db_file_size
))
580 int64
DatabaseTracker::SeedOpenDatabaseInfo(
581 const std::string
& origin_id
, const base::string16
& name
,
582 const base::string16
& description
) {
583 DCHECK(database_connections_
.IsDatabaseOpened(origin_id
, name
));
584 int64 size
= GetDBFileSize(origin_id
, name
);
585 database_connections_
.SetOpenDatabaseSize(origin_id
, name
, size
);
586 CachedOriginInfo
* info
= MaybeGetCachedOriginInfo(origin_id
, false);
588 info
->SetDatabaseSize(name
, size
);
589 info
->SetDatabaseDescription(name
, description
);
594 int64
DatabaseTracker::UpdateOpenDatabaseInfoAndNotify(
595 const std::string
& origin_id
, const base::string16
& name
,
596 const base::string16
* opt_description
) {
597 DCHECK(database_connections_
.IsDatabaseOpened(origin_id
, name
));
598 int64 new_size
= GetDBFileSize(origin_id
, name
);
599 int64 old_size
= database_connections_
.GetOpenDatabaseSize(origin_id
, name
);
600 CachedOriginInfo
* info
= MaybeGetCachedOriginInfo(origin_id
, false);
601 if (info
&& opt_description
)
602 info
->SetDatabaseDescription(name
, *opt_description
);
603 if (old_size
!= new_size
) {
604 database_connections_
.SetOpenDatabaseSize(origin_id
, name
, new_size
);
606 info
->SetDatabaseSize(name
, new_size
);
607 if (quota_manager_proxy_
.get())
608 quota_manager_proxy_
->NotifyStorageModified(
609 storage::QuotaClient::kDatabase
,
610 storage::GetOriginFromIdentifier(origin_id
),
611 storage::kStorageTypeTemporary
,
612 new_size
- old_size
);
613 FOR_EACH_OBSERVER(Observer
, observers_
, OnDatabaseSizeChanged(
614 origin_id
, name
, new_size
));
619 void DatabaseTracker::ScheduleDatabaseForDeletion(
620 const std::string
& origin_identifier
,
621 const base::string16
& database_name
) {
622 DCHECK(database_connections_
.IsDatabaseOpened(origin_identifier
,
624 dbs_to_be_deleted_
[origin_identifier
].insert(database_name
);
625 FOR_EACH_OBSERVER(Observer
, observers_
, OnDatabaseScheduledForDeletion(
626 origin_identifier
, database_name
));
629 void DatabaseTracker::ScheduleDatabasesForDeletion(
630 const DatabaseSet
& databases
,
631 const net::CompletionCallback
& callback
) {
632 DCHECK(!databases
.empty());
634 if (!callback
.is_null())
635 deletion_callbacks_
.push_back(std::make_pair(callback
, databases
));
636 for (DatabaseSet::const_iterator ori
= databases
.begin();
637 ori
!= databases
.end(); ++ori
) {
638 for (std::set
<base::string16
>::const_iterator db
= ori
->second
.begin();
639 db
!= ori
->second
.end(); ++db
)
640 ScheduleDatabaseForDeletion(ori
->first
, *db
);
644 int DatabaseTracker::DeleteDatabase(const std::string
& origin_identifier
,
645 const base::string16
& database_name
,
646 const net::CompletionCallback
& callback
) {
648 return net::ERR_FAILED
;
650 if (database_connections_
.IsDatabaseOpened(origin_identifier
,
652 if (!callback
.is_null()) {
654 set
[origin_identifier
].insert(database_name
);
655 deletion_callbacks_
.push_back(std::make_pair(callback
, set
));
657 ScheduleDatabaseForDeletion(origin_identifier
, database_name
);
658 return net::ERR_IO_PENDING
;
660 DeleteClosedDatabase(origin_identifier
, database_name
);
664 int DatabaseTracker::DeleteDataModifiedSince(
665 const base::Time
& cutoff
,
666 const net::CompletionCallback
& callback
) {
668 return net::ERR_FAILED
;
670 DatabaseSet to_be_deleted
;
672 std::vector
<std::string
> origins_identifiers
;
673 if (!databases_table_
->GetAllOriginIdentifiers(&origins_identifiers
))
674 return net::ERR_FAILED
;
676 for (std::vector
<std::string
>::const_iterator ori
=
677 origins_identifiers
.begin();
678 ori
!= origins_identifiers
.end(); ++ori
) {
679 if (special_storage_policy_
.get() &&
680 special_storage_policy_
->IsStorageProtected(
681 storage::GetOriginFromIdentifier(*ori
))) {
685 std::vector
<DatabaseDetails
> details
;
686 if (!databases_table_
->
687 GetAllDatabaseDetailsForOriginIdentifier(*ori
, &details
))
688 rv
= net::ERR_FAILED
;
689 for (std::vector
<DatabaseDetails
>::const_iterator db
= details
.begin();
690 db
!= details
.end(); ++db
) {
691 base::FilePath db_file
= GetFullDBFilePath(*ori
, db
->database_name
);
692 base::File::Info file_info
;
693 base::GetFileInfo(db_file
, &file_info
);
694 if (file_info
.last_modified
< cutoff
)
697 // Check if the database is opened by any renderer.
698 if (database_connections_
.IsDatabaseOpened(*ori
, db
->database_name
))
699 to_be_deleted
[*ori
].insert(db
->database_name
);
701 DeleteClosedDatabase(*ori
, db
->database_name
);
708 if (!to_be_deleted
.empty()) {
709 ScheduleDatabasesForDeletion(to_be_deleted
, callback
);
710 return net::ERR_IO_PENDING
;
715 int DatabaseTracker::DeleteDataForOrigin(
716 const std::string
& origin
, const net::CompletionCallback
& callback
) {
718 return net::ERR_FAILED
;
720 DatabaseSet to_be_deleted
;
722 std::vector
<DatabaseDetails
> details
;
723 if (!databases_table_
->
724 GetAllDatabaseDetailsForOriginIdentifier(origin
, &details
))
725 return net::ERR_FAILED
;
726 for (std::vector
<DatabaseDetails
>::const_iterator db
= details
.begin();
727 db
!= details
.end(); ++db
) {
728 // Check if the database is opened by any renderer.
729 if (database_connections_
.IsDatabaseOpened(origin
, db
->database_name
))
730 to_be_deleted
[origin
].insert(db
->database_name
);
732 DeleteClosedDatabase(origin
, db
->database_name
);
735 if (!to_be_deleted
.empty()) {
736 ScheduleDatabasesForDeletion(to_be_deleted
, callback
);
737 return net::ERR_IO_PENDING
;
742 const base::File
* DatabaseTracker::GetIncognitoFile(
743 const base::string16
& vfs_file_name
) const {
744 DCHECK(is_incognito_
);
745 FileHandlesMap::const_iterator it
=
746 incognito_file_handles_
.find(vfs_file_name
);
747 if (it
!= incognito_file_handles_
.end())
753 const base::File
* DatabaseTracker::SaveIncognitoFile(
754 const base::string16
& vfs_file_name
,
756 DCHECK(is_incognito_
);
760 base::File
* to_insert
= new base::File(file
.Pass());
761 std::pair
<FileHandlesMap::iterator
, bool> rv
=
762 incognito_file_handles_
.insert(std::make_pair(vfs_file_name
, to_insert
));
764 return rv
.first
->second
;
767 void DatabaseTracker::CloseIncognitoFileHandle(
768 const base::string16
& vfs_file_name
) {
769 DCHECK(is_incognito_
);
770 DCHECK(incognito_file_handles_
.find(vfs_file_name
) !=
771 incognito_file_handles_
.end());
773 FileHandlesMap::iterator it
= incognito_file_handles_
.find(vfs_file_name
);
774 if (it
!= incognito_file_handles_
.end()) {
776 incognito_file_handles_
.erase(it
);
780 bool DatabaseTracker::HasSavedIncognitoFileHandle(
781 const base::string16
& vfs_file_name
) const {
782 return (incognito_file_handles_
.find(vfs_file_name
) !=
783 incognito_file_handles_
.end());
786 void DatabaseTracker::DeleteIncognitoDBDirectory() {
787 is_initialized_
= false;
789 for (FileHandlesMap::iterator it
= incognito_file_handles_
.begin();
790 it
!= incognito_file_handles_
.end(); it
++) {
794 base::FilePath incognito_db_dir
=
795 profile_path_
.Append(kIncognitoDatabaseDirectoryName
);
796 if (base::DirectoryExists(incognito_db_dir
))
797 base::DeleteFile(incognito_db_dir
, true);
800 void DatabaseTracker::ClearSessionOnlyOrigins() {
801 bool has_session_only_databases
=
802 special_storage_policy_
.get() &&
803 special_storage_policy_
->HasSessionOnlyOrigins();
805 // Clearing only session-only databases, and there are none.
806 if (!has_session_only_databases
)
812 std::vector
<std::string
> origin_identifiers
;
813 GetAllOriginIdentifiers(&origin_identifiers
);
815 for (std::vector
<std::string
>::iterator origin
=
816 origin_identifiers
.begin();
817 origin
!= origin_identifiers
.end(); ++origin
) {
818 GURL origin_url
= storage::GetOriginFromIdentifier(*origin
);
819 if (!special_storage_policy_
->IsStorageSessionOnly(origin_url
))
821 if (special_storage_policy_
->IsStorageProtected(origin_url
))
823 storage::OriginInfo origin_info
;
824 std::vector
<base::string16
> databases
;
825 GetOriginInfo(*origin
, &origin_info
);
826 origin_info
.GetAllDatabaseNames(&databases
);
828 for (std::vector
<base::string16
>::iterator database
= databases
.begin();
829 database
!= databases
.end(); ++database
) {
830 base::File
file(GetFullDBFilePath(*origin
, *database
),
831 base::File::FLAG_OPEN_ALWAYS
|
832 base::File::FLAG_SHARE_DELETE
|
833 base::File::FLAG_DELETE_ON_CLOSE
|
834 base::File::FLAG_READ
);
836 DeleteOrigin(*origin
, true);
841 void DatabaseTracker::Shutdown() {
842 DCHECK(db_tracker_thread_
.get());
843 DCHECK(db_tracker_thread_
->BelongsToCurrentThread());
844 if (shutting_down_
) {
848 shutting_down_
= true;
850 DeleteIncognitoDBDirectory();
851 else if (!force_keep_session_state_
)
852 ClearSessionOnlyOrigins();
853 CloseTrackerDatabaseAndClearCaches();
856 void DatabaseTracker::SetForceKeepSessionState() {
857 DCHECK(db_tracker_thread_
.get());
858 if (!db_tracker_thread_
->BelongsToCurrentThread()) {
859 db_tracker_thread_
->PostTask(
861 base::Bind(&DatabaseTracker::SetForceKeepSessionState
, this));
864 force_keep_session_state_
= true;
867 } // namespace storage