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/strings/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 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_(origin_info
.origin_
),
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 base::string16
& origin
, int64 total_size
)
78 : origin_(origin
), total_size_(total_size
) {}
80 DatabaseTracker::DatabaseTracker(
81 const base::FilePath
& profile_path
,
83 quota::SpecialStoragePolicy
* special_storage_policy
,
84 quota::QuotaManagerProxy
* quota_manager_proxy
,
85 base::MessageLoopProxy
* 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
),
91 db_dir_(is_incognito_
?
92 profile_path_
.Append(kIncognitoDatabaseDirectoryName
) :
93 profile_path_
.Append(kDatabaseDirectoryName
)),
94 db_(new sql::Connection()),
95 databases_table_(NULL
),
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));
107 DatabaseTracker::~DatabaseTracker() {
108 DCHECK(dbs_to_be_deleted_
.empty());
109 DCHECK(deletion_callbacks_
.empty());
112 void DatabaseTracker::DatabaseOpened(const base::string16
& 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()) {
122 if (quota_manager_proxy_
)
123 quota_manager_proxy_
->NotifyStorageAccessed(
124 quota::QuotaClient::kDatabase
,
125 DatabaseUtil::GetOriginFromIdentifier(origin_identifier
),
126 quota::kStorageTypeTemporary
);
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
,
133 database_description
);
136 *database_size
= UpdateOpenDatabaseInfoAndNotify(origin_identifier
,
138 &database_description
);
141 void DatabaseTracker::DatabaseModified(const base::string16
& origin_identifier
,
142 const base::string16
& database_name
) {
145 UpdateOpenDatabaseSizeAndNotify(origin_identifier
, database_name
);
148 void DatabaseTracker::DatabaseClosed(const base::string16
& origin_identifier
,
149 const base::string16
& database_name
) {
150 if (database_connections_
.IsEmpty()) {
151 DCHECK(!is_initialized_
);
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_
)
158 quota_manager_proxy_
->NotifyStorageAccessed(
159 quota::QuotaClient::kDatabase
,
160 DatabaseUtil::GetOriginFromIdentifier(origin_identifier
),
161 quota::kStorageTypeTemporary
);
163 UpdateOpenDatabaseSizeAndNotify(origin_identifier
, database_name
);
164 if (database_connections_
.RemoveConnection(origin_identifier
, database_name
))
165 DeleteDatabaseIfNeeded(origin_identifier
, database_name
);
168 void DatabaseTracker::HandleSqliteError(
169 const base::string16
& origin_identifier
,
170 const base::string16
& database_name
,
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());
186 void DatabaseTracker::CloseDatabases(const DatabaseConnections
& connections
) {
187 if (database_connections_
.IsEmpty()) {
188 DCHECK(!is_initialized_
|| connections
.IsEmpty());
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
<base::string16
, base::string16
> > open_dbs
;
199 connections
.ListConnections(&open_dbs
);
200 for (std::vector
<std::pair
<base::string16
, base::string16
> >::iterator it
=
201 open_dbs
.begin(); it
!= open_dbs
.end(); ++it
)
202 UpdateOpenDatabaseSizeAndNotify(it
->first
, it
->second
);
204 std::vector
<std::pair
<base::string16
, base::string16
> > closed_dbs
;
205 database_connections_
.RemoveConnections(connections
, &closed_dbs
);
206 for (std::vector
<std::pair
<base::string16
, base::string16
> >::iterator it
=
207 closed_dbs
.begin(); it
!= closed_dbs
.end(); ++it
) {
208 DeleteDatabaseIfNeeded(it
->first
, it
->second
);
212 void DatabaseTracker::DeleteDatabaseIfNeeded(
213 const base::string16
& origin_identifier
,
214 const base::string16
& database_name
) {
215 DCHECK(!database_connections_
.IsDatabaseOpened(origin_identifier
,
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
);
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
;
235 callback
= deletion_callbacks_
.erase(callback
);
246 void DatabaseTracker::AddObserver(Observer
* observer
) {
247 observers_
.AddObserver(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();
258 void DatabaseTracker::CloseTrackerDatabaseAndClearCaches() {
259 ClearAllCachedOriginInfo();
261 if (!is_incognito_
) {
262 meta_table_
.reset(NULL
);
263 databases_table_
.reset(NULL
);
265 is_initialized_
= false;
269 base::string16
DatabaseTracker::GetOriginDirectory(
270 const base::string16
& origin_identifier
) {
272 return origin_identifier
;
274 OriginDirectoriesMap::const_iterator it
=
275 incognito_origin_directories_
.find(origin_identifier
);
276 if (it
!= incognito_origin_directories_
.end())
279 base::string16 origin_directory
=
280 base::IntToString16(incognito_origin_directories_generator_
++);
281 incognito_origin_directories_
[origin_identifier
] = origin_directory
;
282 return origin_directory
;
285 base::FilePath
DatabaseTracker::GetFullDBFilePath(
286 const base::string16
& origin_identifier
,
287 const base::string16
& database_name
) {
288 DCHECK(!origin_identifier
.empty());
290 return base::FilePath();
292 int64 id
= databases_table_
->GetDatabaseID(
293 origin_identifier
, database_name
);
295 return base::FilePath();
297 base::FilePath file_name
= base::FilePath::FromWStringHack(
298 UTF8ToWide(base::Int64ToString(id
)));
299 return db_dir_
.Append(base::FilePath::FromWStringHack(
300 UTF16ToWide(GetOriginDirectory(origin_identifier
)))).Append(file_name
);
303 bool DatabaseTracker::GetOriginInfo(const base::string16
& origin_identifier
,
306 CachedOriginInfo
* cached_info
= GetCachedOriginInfo(origin_identifier
);
309 *info
= OriginInfo(*cached_info
);
313 bool DatabaseTracker::GetAllOriginIdentifiers(
314 std::vector
<base::string16
>* origin_identifiers
) {
315 DCHECK(origin_identifiers
);
316 DCHECK(origin_identifiers
->empty());
319 return databases_table_
->GetAllOrigins(origin_identifiers
);
322 bool DatabaseTracker::GetAllOriginsInfo(
323 std::vector
<OriginInfo
>* origins_info
) {
324 DCHECK(origins_info
);
325 DCHECK(origins_info
->empty());
327 std::vector
<base::string16
> origins
;
328 if (!GetAllOriginIdentifiers(&origins
))
331 for (std::vector
<base::string16
>::const_iterator it
= origins
.begin();
332 it
!= origins
.end(); it
++) {
333 CachedOriginInfo
* origin_info
= GetCachedOriginInfo(*it
);
335 // Restore 'origins_info' to its initial state.
336 origins_info
->clear();
339 origins_info
->push_back(OriginInfo(*origin_info
));
345 bool DatabaseTracker::DeleteClosedDatabase(
346 const base::string16
& origin_identifier
,
347 const base::string16
& database_name
) {
351 // Check if the database is opened by any renderer.
352 if (database_connections_
.IsDatabaseOpened(origin_identifier
, database_name
))
355 int64 db_file_size
= quota_manager_proxy_
?
356 GetDBFileSize(origin_identifier
, database_name
) : 0;
358 // Try to delete the file on the hard drive.
359 base::FilePath db_file
= GetFullDBFilePath(origin_identifier
, database_name
);
360 if (file_util::PathExists(db_file
) && !file_util::Delete(db_file
, false))
363 // Also delete any orphaned journal file.
364 DCHECK(db_file
.Extension().empty());
365 file_util::Delete(db_file
.InsertBeforeExtensionASCII(
366 DatabaseUtil::kJournalFileSuffix
), false);
368 if (quota_manager_proxy_
&& db_file_size
)
369 quota_manager_proxy_
->NotifyStorageModified(
370 quota::QuotaClient::kDatabase
,
371 DatabaseUtil::GetOriginFromIdentifier(origin_identifier
),
372 quota::kStorageTypeTemporary
,
375 // Clean up the main database and invalidate the cached record.
376 databases_table_
->DeleteDatabaseDetails(origin_identifier
, database_name
);
377 origins_info_map_
.erase(origin_identifier
);
379 std::vector
<DatabaseDetails
> details
;
380 if (databases_table_
->GetAllDatabaseDetailsForOrigin(
381 origin_identifier
, &details
) && details
.empty()) {
382 // Try to delete the origin in case this was the last database.
383 DeleteOrigin(origin_identifier
, false);
388 bool DatabaseTracker::DeleteOrigin(const base::string16
& origin_identifier
,
393 // Check if any database in this origin is opened by any renderer.
394 if (database_connections_
.IsOriginUsed(origin_identifier
) && !force
)
397 int64 deleted_size
= 0;
398 if (quota_manager_proxy_
) {
399 CachedOriginInfo
* origin_info
= GetCachedOriginInfo(origin_identifier
);
401 deleted_size
= origin_info
->TotalSize();
404 origins_info_map_
.erase(origin_identifier
);
405 base::FilePath origin_dir
= db_dir_
.Append(base::FilePath::FromWStringHack(
406 UTF16ToWide(origin_identifier
)));
408 // Create a temporary directory to move possibly still existing databases to,
409 // as we can't delete the origin directory on windows if it contains opened
411 base::FilePath new_origin_dir
;
412 file_util::CreateTemporaryDirInDir(db_dir_
,
413 kTemporaryDirectoryPrefix
,
415 file_util::FileEnumerator
databases(
418 file_util::FileEnumerator::FILES
);
419 for (base::FilePath database
= databases
.Next(); !database
.empty();
420 database
= databases
.Next()) {
421 base::FilePath new_file
= new_origin_dir
.Append(database
.BaseName());
422 file_util::Move(database
, new_file
);
424 file_util::Delete(origin_dir
, true);
425 file_util::Delete(new_origin_dir
, true); // might fail on windows.
427 databases_table_
->DeleteOrigin(origin_identifier
);
429 if (quota_manager_proxy_
&& deleted_size
) {
430 quota_manager_proxy_
->NotifyStorageModified(
431 quota::QuotaClient::kDatabase
,
432 DatabaseUtil::GetOriginFromIdentifier(origin_identifier
),
433 quota::kStorageTypeTemporary
,
440 bool DatabaseTracker::IsDatabaseScheduledForDeletion(
441 const base::string16
& origin_identifier
,
442 const base::string16
& database_name
) {
443 DatabaseSet::iterator it
= dbs_to_be_deleted_
.find(origin_identifier
);
444 if (it
== dbs_to_be_deleted_
.end())
447 std::set
<base::string16
>& databases
= it
->second
;
448 return (databases
.find(database_name
) != databases
.end());
451 bool DatabaseTracker::LazyInit() {
452 if (!is_initialized_
&& !shutting_down_
) {
453 DCHECK(!db_
->is_open());
454 DCHECK(!databases_table_
.get());
455 DCHECK(!meta_table_
.get());
457 // If there are left-over directories from failed deletion attempts, clean
459 if (file_util::DirectoryExists(db_dir_
)) {
460 file_util::FileEnumerator
directories(
463 file_util::FileEnumerator::DIRECTORIES
,
464 kTemporaryDirectoryPattern
);
465 for (base::FilePath directory
= directories
.Next(); !directory
.empty();
466 directory
= directories
.Next()) {
467 file_util::Delete(directory
, true);
471 // If the tracker database exists, but it's corrupt or doesn't
472 // have a meta table, delete the database directory.
473 const base::FilePath kTrackerDatabaseFullPath
=
474 db_dir_
.Append(base::FilePath(kTrackerDatabaseFileName
));
475 if (file_util::DirectoryExists(db_dir_
) &&
476 file_util::PathExists(kTrackerDatabaseFullPath
) &&
477 (!db_
->Open(kTrackerDatabaseFullPath
) ||
478 !sql::MetaTable::DoesTableExist(db_
.get()))) {
480 if (!file_util::Delete(db_dir_
, true))
484 db_
->set_error_histogram_name("Sqlite.DatabaseTracker.Error");
486 databases_table_
.reset(new DatabasesTable(db_
.get()));
487 meta_table_
.reset(new sql::MetaTable());
490 file_util::CreateDirectory(db_dir_
) &&
492 (is_incognito_
? db_
->OpenInMemory() :
493 db_
->Open(kTrackerDatabaseFullPath
))) &&
494 UpgradeToCurrentVersion();
495 if (!is_initialized_
) {
496 databases_table_
.reset(NULL
);
497 meta_table_
.reset(NULL
);
501 return is_initialized_
;
504 bool DatabaseTracker::UpgradeToCurrentVersion() {
505 sql::Transaction
transaction(db_
.get());
506 if (!transaction
.Begin() ||
507 !meta_table_
->Init(db_
.get(), kCurrentVersion
, kCompatibleVersion
) ||
508 (meta_table_
->GetCompatibleVersionNumber() > kCurrentVersion
) ||
509 !databases_table_
->Init())
512 if (meta_table_
->GetVersionNumber() < kCurrentVersion
)
513 meta_table_
->SetVersionNumber(kCurrentVersion
);
515 return transaction
.Commit();
518 void DatabaseTracker::InsertOrUpdateDatabaseDetails(
519 const base::string16
& origin_identifier
,
520 const base::string16
& database_name
,
521 const base::string16
& database_description
,
522 int64 estimated_size
) {
523 DatabaseDetails details
;
524 if (!databases_table_
->GetDatabaseDetails(
525 origin_identifier
, database_name
, &details
)) {
526 details
.origin_identifier
= origin_identifier
;
527 details
.database_name
= database_name
;
528 details
.description
= database_description
;
529 details
.estimated_size
= estimated_size
;
530 databases_table_
->InsertDatabaseDetails(details
);
531 } else if ((details
.description
!= database_description
) ||
532 (details
.estimated_size
!= estimated_size
)) {
533 details
.description
= database_description
;
534 details
.estimated_size
= estimated_size
;
535 databases_table_
->UpdateDatabaseDetails(details
);
539 void DatabaseTracker::ClearAllCachedOriginInfo() {
540 origins_info_map_
.clear();
543 DatabaseTracker::CachedOriginInfo
* DatabaseTracker::MaybeGetCachedOriginInfo(
544 const base::string16
& origin_identifier
, bool create_if_needed
) {
548 // Populate the cache with data for this origin if needed.
549 if (origins_info_map_
.find(origin_identifier
) == origins_info_map_
.end()) {
550 if (!create_if_needed
)
553 std::vector
<DatabaseDetails
> details
;
554 if (!databases_table_
->GetAllDatabaseDetailsForOrigin(
555 origin_identifier
, &details
)) {
559 CachedOriginInfo
& origin_info
= origins_info_map_
[origin_identifier
];
560 origin_info
.SetOrigin(origin_identifier
);
561 for (std::vector
<DatabaseDetails
>::const_iterator it
= details
.begin();
562 it
!= details
.end(); it
++) {
564 if (database_connections_
.IsDatabaseOpened(
565 origin_identifier
, it
->database_name
)) {
566 db_file_size
= database_connections_
.GetOpenDatabaseSize(
567 origin_identifier
, it
->database_name
);
569 db_file_size
= GetDBFileSize(origin_identifier
, it
->database_name
);
571 origin_info
.SetDatabaseSize(it
->database_name
, db_file_size
);
572 origin_info
.SetDatabaseDescription(it
->database_name
, it
->description
);
576 return &origins_info_map_
[origin_identifier
];
579 int64
DatabaseTracker::GetDBFileSize(const base::string16
& origin_identifier
,
580 const base::string16
& database_name
) {
581 base::FilePath db_file_name
= GetFullDBFilePath(origin_identifier
,
583 int64 db_file_size
= 0;
584 if (!file_util::GetFileSize(db_file_name
, &db_file_size
))
589 int64
DatabaseTracker::SeedOpenDatabaseInfo(
590 const base::string16
& origin_id
, const base::string16
& name
,
591 const base::string16
& description
) {
592 DCHECK(database_connections_
.IsDatabaseOpened(origin_id
, name
));
593 int64 size
= GetDBFileSize(origin_id
, name
);
594 database_connections_
.SetOpenDatabaseSize(origin_id
, name
, size
);
595 CachedOriginInfo
* info
= MaybeGetCachedOriginInfo(origin_id
, false);
597 info
->SetDatabaseSize(name
, size
);
598 info
->SetDatabaseDescription(name
, description
);
603 int64
DatabaseTracker::UpdateOpenDatabaseInfoAndNotify(
604 const base::string16
& origin_id
, const base::string16
& name
,
605 const base::string16
* opt_description
) {
606 DCHECK(database_connections_
.IsDatabaseOpened(origin_id
, name
));
607 int64 new_size
= GetDBFileSize(origin_id
, name
);
608 int64 old_size
= database_connections_
.GetOpenDatabaseSize(origin_id
, name
);
609 CachedOriginInfo
* info
= MaybeGetCachedOriginInfo(origin_id
, false);
610 if (info
&& opt_description
)
611 info
->SetDatabaseDescription(name
, *opt_description
);
612 if (old_size
!= new_size
) {
613 database_connections_
.SetOpenDatabaseSize(origin_id
, name
, new_size
);
615 info
->SetDatabaseSize(name
, new_size
);
616 if (quota_manager_proxy_
)
617 quota_manager_proxy_
->NotifyStorageModified(
618 quota::QuotaClient::kDatabase
,
619 DatabaseUtil::GetOriginFromIdentifier(origin_id
),
620 quota::kStorageTypeTemporary
,
621 new_size
- old_size
);
622 FOR_EACH_OBSERVER(Observer
, observers_
, OnDatabaseSizeChanged(
623 origin_id
, name
, new_size
));
628 void DatabaseTracker::ScheduleDatabaseForDeletion(
629 const base::string16
& origin_identifier
,
630 const base::string16
& database_name
) {
631 DCHECK(database_connections_
.IsDatabaseOpened(origin_identifier
,
633 dbs_to_be_deleted_
[origin_identifier
].insert(database_name
);
634 FOR_EACH_OBSERVER(Observer
, observers_
, OnDatabaseScheduledForDeletion(
635 origin_identifier
, database_name
));
638 void DatabaseTracker::ScheduleDatabasesForDeletion(
639 const DatabaseSet
& databases
,
640 const net::CompletionCallback
& callback
) {
641 DCHECK(!databases
.empty());
643 if (!callback
.is_null())
644 deletion_callbacks_
.push_back(std::make_pair(callback
, databases
));
645 for (DatabaseSet::const_iterator ori
= databases
.begin();
646 ori
!= databases
.end(); ++ori
) {
647 for (std::set
<base::string16
>::const_iterator db
= ori
->second
.begin();
648 db
!= ori
->second
.end(); ++db
)
649 ScheduleDatabaseForDeletion(ori
->first
, *db
);
653 int DatabaseTracker::DeleteDatabase(const base::string16
& origin_identifier
,
654 const base::string16
& database_name
,
655 const net::CompletionCallback
& callback
) {
657 return net::ERR_FAILED
;
659 if (database_connections_
.IsDatabaseOpened(origin_identifier
,
661 if (!callback
.is_null()) {
663 set
[origin_identifier
].insert(database_name
);
664 deletion_callbacks_
.push_back(std::make_pair(callback
, set
));
666 ScheduleDatabaseForDeletion(origin_identifier
, database_name
);
667 return net::ERR_IO_PENDING
;
669 DeleteClosedDatabase(origin_identifier
, database_name
);
673 int DatabaseTracker::DeleteDataModifiedSince(
674 const base::Time
& cutoff
,
675 const net::CompletionCallback
& callback
) {
677 return net::ERR_FAILED
;
679 DatabaseSet to_be_deleted
;
681 std::vector
<base::string16
> origins_identifiers
;
682 if (!databases_table_
->GetAllOrigins(&origins_identifiers
))
683 return net::ERR_FAILED
;
685 for (std::vector
<base::string16
>::const_iterator ori
=
686 origins_identifiers
.begin();
687 ori
!= origins_identifiers
.end(); ++ori
) {
688 if (special_storage_policy_
.get() &&
689 special_storage_policy_
->IsStorageProtected(
690 DatabaseUtil::GetOriginFromIdentifier(*ori
))) {
694 std::vector
<DatabaseDetails
> details
;
695 if (!databases_table_
->GetAllDatabaseDetailsForOrigin(*ori
, &details
))
696 rv
= net::ERR_FAILED
;
697 for (std::vector
<DatabaseDetails
>::const_iterator db
= details
.begin();
698 db
!= details
.end(); ++db
) {
699 base::FilePath db_file
= GetFullDBFilePath(*ori
, db
->database_name
);
700 base::PlatformFileInfo file_info
;
701 file_util::GetFileInfo(db_file
, &file_info
);
702 if (file_info
.last_modified
< cutoff
)
705 // Check if the database is opened by any renderer.
706 if (database_connections_
.IsDatabaseOpened(*ori
, db
->database_name
))
707 to_be_deleted
[*ori
].insert(db
->database_name
);
709 DeleteClosedDatabase(*ori
, db
->database_name
);
716 if (!to_be_deleted
.empty()) {
717 ScheduleDatabasesForDeletion(to_be_deleted
, callback
);
718 return net::ERR_IO_PENDING
;
723 int DatabaseTracker::DeleteDataForOrigin(
724 const base::string16
& origin
, const net::CompletionCallback
& callback
) {
726 return net::ERR_FAILED
;
728 DatabaseSet to_be_deleted
;
730 std::vector
<DatabaseDetails
> details
;
731 if (!databases_table_
->GetAllDatabaseDetailsForOrigin(origin
, &details
))
732 return net::ERR_FAILED
;
733 for (std::vector
<DatabaseDetails
>::const_iterator db
= details
.begin();
734 db
!= details
.end(); ++db
) {
735 // Check if the database is opened by any renderer.
736 if (database_connections_
.IsDatabaseOpened(origin
, db
->database_name
))
737 to_be_deleted
[origin
].insert(db
->database_name
);
739 DeleteClosedDatabase(origin
, db
->database_name
);
742 if (!to_be_deleted
.empty()) {
743 ScheduleDatabasesForDeletion(to_be_deleted
, callback
);
744 return net::ERR_IO_PENDING
;
749 void DatabaseTracker::GetIncognitoFileHandle(
750 const base::string16
& vfs_file_name
,
751 base::PlatformFile
* file_handle
) const {
752 DCHECK(is_incognito_
);
753 FileHandlesMap::const_iterator it
=
754 incognito_file_handles_
.find(vfs_file_name
);
755 if (it
!= incognito_file_handles_
.end())
756 *file_handle
= it
->second
;
758 *file_handle
= base::kInvalidPlatformFileValue
;
761 void DatabaseTracker::SaveIncognitoFileHandle(
762 const base::string16
& vfs_file_name
,
763 const base::PlatformFile
& file_handle
) {
764 DCHECK(is_incognito_
);
765 DCHECK(incognito_file_handles_
.find(vfs_file_name
) ==
766 incognito_file_handles_
.end());
767 if (file_handle
!= base::kInvalidPlatformFileValue
)
768 incognito_file_handles_
[vfs_file_name
] = file_handle
;
771 bool DatabaseTracker::CloseIncognitoFileHandle(
772 const base::string16
& vfs_file_name
) {
773 DCHECK(is_incognito_
);
774 DCHECK(incognito_file_handles_
.find(vfs_file_name
) !=
775 incognito_file_handles_
.end());
777 bool handle_closed
= false;
778 FileHandlesMap::iterator it
= incognito_file_handles_
.find(vfs_file_name
);
779 if (it
!= incognito_file_handles_
.end()) {
780 handle_closed
= base::ClosePlatformFile(it
->second
);
782 incognito_file_handles_
.erase(it
);
784 return handle_closed
;
787 bool DatabaseTracker::HasSavedIncognitoFileHandle(
788 const base::string16
& vfs_file_name
) const {
789 return (incognito_file_handles_
.find(vfs_file_name
) !=
790 incognito_file_handles_
.end());
793 void DatabaseTracker::DeleteIncognitoDBDirectory() {
794 shutting_down_
= true;
795 is_initialized_
= false;
797 for (FileHandlesMap::iterator it
= incognito_file_handles_
.begin();
798 it
!= incognito_file_handles_
.end(); it
++)
799 base::ClosePlatformFile(it
->second
);
801 base::FilePath incognito_db_dir
=
802 profile_path_
.Append(kIncognitoDatabaseDirectoryName
);
803 if (file_util::DirectoryExists(incognito_db_dir
))
804 file_util::Delete(incognito_db_dir
, true);
807 void DatabaseTracker::ClearSessionOnlyOrigins() {
808 shutting_down_
= true;
810 bool has_session_only_databases
=
811 special_storage_policy_
.get() &&
812 special_storage_policy_
->HasSessionOnlyOrigins();
814 // Clearing only session-only databases, and there are none.
815 if (!has_session_only_databases
)
821 std::vector
<base::string16
> origin_identifiers
;
822 GetAllOriginIdentifiers(&origin_identifiers
);
824 for (std::vector
<base::string16
>::iterator origin
=
825 origin_identifiers
.begin();
826 origin
!= origin_identifiers
.end(); ++origin
) {
828 webkit_database::DatabaseUtil::GetOriginFromIdentifier(*origin
);
829 if (!special_storage_policy_
->IsStorageSessionOnly(origin_url
))
831 if (special_storage_policy_
->IsStorageProtected(origin_url
))
833 webkit_database::OriginInfo origin_info
;
834 std::vector
<base::string16
> databases
;
835 GetOriginInfo(*origin
, &origin_info
);
836 origin_info
.GetAllDatabaseNames(&databases
);
838 for (std::vector
<base::string16
>::iterator database
= databases
.begin();
839 database
!= databases
.end(); ++database
) {
840 base::PlatformFile file_handle
= base::CreatePlatformFile(
841 GetFullDBFilePath(*origin
, *database
),
842 base::PLATFORM_FILE_OPEN_ALWAYS
|
843 base::PLATFORM_FILE_SHARE_DELETE
|
844 base::PLATFORM_FILE_DELETE_ON_CLOSE
|
845 base::PLATFORM_FILE_READ
,
847 base::ClosePlatformFile(file_handle
);
849 DeleteOrigin(*origin
, true);
854 void DatabaseTracker::Shutdown() {
855 DCHECK(db_tracker_thread_
.get());
856 DCHECK(db_tracker_thread_
->BelongsToCurrentThread());
857 if (shutting_down_
) {
862 DeleteIncognitoDBDirectory();
863 else if (!force_keep_session_state_
)
864 ClearSessionOnlyOrigins();
867 void DatabaseTracker::SetForceKeepSessionState() {
868 DCHECK(db_tracker_thread_
.get());
869 if (!db_tracker_thread_
->BelongsToCurrentThread()) {
870 db_tracker_thread_
->PostTask(
872 base::Bind(&DatabaseTracker::SetForceKeepSessionState
, this));
875 force_keep_session_state_
= true;
878 } // namespace webkit_database