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