1/*
2 * Copyright (C) 2007, 2008, 2012, 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30#include "DatabaseTracker.h"
31
32#if ENABLE(SQL_DATABASE)
33
34#include "Chrome.h"
35#include "ChromeClient.h"
36#include "Database.h"
37#include "DatabaseBackendBase.h"
38#include "DatabaseBackendContext.h"
39#include "DatabaseManager.h"
40#include "DatabaseManagerClient.h"
41#include "DatabaseThread.h"
42#include "FileSystem.h"
43#include "Logging.h"
44#include "OriginLock.h"
45#include "Page.h"
46#include "SecurityOrigin.h"
47#include "SecurityOriginHash.h"
48#include "SQLiteFileSystem.h"
49#include "SQLiteStatement.h"
50#include <wtf/MainThread.h>
51#include <wtf/NeverDestroyed.h>
52#include <wtf/StdLibExtras.h>
53#include <wtf/text/CString.h>
54
55#if PLATFORM(IOS)
56#include "WebCoreThread.h"
57#endif
58
59namespace WebCore {
60
61static DatabaseTracker* staticTracker = 0;
62
63void DatabaseTracker::initializeTracker(const String& databasePath)
64{
65    ASSERT(!staticTracker);
66    if (staticTracker)
67        return;
68
69    staticTracker = new DatabaseTracker(databasePath);
70}
71
72DatabaseTracker& DatabaseTracker::tracker()
73{
74    if (!staticTracker)
75        staticTracker = new DatabaseTracker("");
76
77    return *staticTracker;
78}
79
80DatabaseTracker::DatabaseTracker(const String& databasePath)
81    : m_client(0)
82{
83    setDatabaseDirectoryPath(databasePath);
84}
85
86void DatabaseTracker::setDatabaseDirectoryPath(const String& path)
87{
88    MutexLocker lockDatabase(m_databaseGuard);
89    ASSERT(!m_database.isOpen());
90    m_databaseDirectoryPath = path.isolatedCopy();
91}
92
93String DatabaseTracker::databaseDirectoryPath() const
94{
95    return m_databaseDirectoryPath.isolatedCopy();
96}
97
98String DatabaseTracker::trackerDatabasePath() const
99{
100    return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath.isolatedCopy(), "Databases.db");
101}
102
103void DatabaseTracker::openTrackerDatabase(TrackerCreationAction createAction)
104{
105    ASSERT(!m_databaseGuard.tryLock());
106
107    if (m_database.isOpen())
108        return;
109
110    // If createIfDoesNotExist is false, SQLiteFileSystem::ensureDatabaseFileExists()
111    // will return false if the database file does not exist.
112    // If createIfDoesNotExist is true, SQLiteFileSystem::ensureDatabaseFileExists()
113    // will attempt to create the path to the database file if it does not
114    // exists yet. It'll return true if the path already exists, or if it
115    // successfully creates the path. Else, it will return false.
116    String databasePath = trackerDatabasePath();
117    if (!SQLiteFileSystem::ensureDatabaseFileExists(databasePath, createAction == CreateIfDoesNotExist))
118        return;
119
120    if (!m_database.open(databasePath)) {
121        // FIXME: What do do here?
122        LOG_ERROR("Failed to open databasePath %s.", databasePath.ascii().data());
123        return;
124    }
125    m_database.disableThreadingChecks();
126
127    if (!m_database.tableExists("Origins")) {
128        if (!m_database.executeCommand("CREATE TABLE Origins (origin TEXT UNIQUE ON CONFLICT REPLACE, quota INTEGER NOT NULL ON CONFLICT FAIL);")) {
129            // FIXME: and here
130            LOG_ERROR("Failed to create Origins table");
131        }
132    }
133
134    if (!m_database.tableExists("Databases")) {
135        if (!m_database.executeCommand("CREATE TABLE Databases (guid INTEGER PRIMARY KEY AUTOINCREMENT, origin TEXT, name TEXT, displayName TEXT, estimatedSize INTEGER, path TEXT);")) {
136            // FIXME: and here
137            LOG_ERROR("Failed to create Databases table");
138        }
139    }
140}
141
142bool DatabaseTracker::hasAdequateQuotaForOrigin(SecurityOrigin* origin, unsigned long estimatedSize, DatabaseError& err)
143{
144    ASSERT(!m_databaseGuard.tryLock());
145    unsigned long long usage = usageForOrigin(origin);
146
147    // If the database will fit, allow its creation.
148    unsigned long long requirement = usage + std::max<unsigned long long>(1, estimatedSize);
149    if (requirement < usage) {
150        // The estimated size is so big it causes an overflow; don't allow creation.
151        err = DatabaseError::DatabaseSizeOverflowed;
152        return false;
153    }
154    if (requirement <= quotaForOriginNoLock(origin))
155        return true;
156
157    err = DatabaseError::DatabaseSizeExceededQuota;
158    return false;
159}
160
161bool DatabaseTracker::canEstablishDatabase(DatabaseBackendContext* context, const String& name, unsigned long estimatedSize, DatabaseError& error)
162{
163    error = DatabaseError::None;
164
165    MutexLocker lockDatabase(m_databaseGuard);
166    SecurityOrigin* origin = context->securityOrigin();
167
168    if (isDeletingDatabaseOrOriginFor(origin, name)) {
169        error = DatabaseError::DatabaseIsBeingDeleted;
170        return false;
171    }
172
173    recordCreatingDatabase(origin, name);
174
175    // If a database already exists, ignore the passed-in estimated size and say it's OK.
176    if (hasEntryForDatabase(origin, name))
177        return true;
178
179    if (hasAdequateQuotaForOrigin(origin, estimatedSize, error)) {
180        ASSERT(error == DatabaseError::None);
181        return true;
182    }
183
184    // If we get here, then we do not have enough quota for one of the
185    // following reasons as indicated by the set error:
186    //
187    // If the error is DatabaseSizeOverflowed, then this means the requested
188    // estimatedSize if so unreasonably large that it can cause an overflow in
189    // the usage budget computation. In that case, there's nothing more we can
190    // do, and there's no need for a retry. Hence, we should indicate that
191    // we're done with our attempt to create the database.
192    //
193    // If the error is DatabaseSizeExceededQuota, then we'll give the client
194    // a chance to update the quota and call retryCanEstablishDatabase() to try
195    // again. Hence, we don't call doneCreatingDatabase() yet in that case.
196
197    if (error == DatabaseError::DatabaseSizeOverflowed)
198        doneCreatingDatabase(origin, name);
199    else
200        ASSERT(error == DatabaseError::DatabaseSizeExceededQuota);
201
202    return false;
203}
204
205// Note: a thought about performance: hasAdequateQuotaForOrigin() was also
206// called in canEstablishDatabase(), and hence, we're repeating some work within
207// hasAdequateQuotaForOrigin(). However, retryCanEstablishDatabase() should only
208// be called in the rare even if canEstablishDatabase() fails. Since it is rare,
209// we should not bother optimizing it. It is more beneficial to keep
210// hasAdequateQuotaForOrigin() simple and correct (i.e. bug free), and just
211// re-use it. Also note that the path for opening a database involves IO, and
212// hence should not be a performance critical path anyway.
213bool DatabaseTracker::retryCanEstablishDatabase(DatabaseBackendContext* context, const String& name, unsigned long estimatedSize, DatabaseError& error)
214{
215    error = DatabaseError::None;
216
217    MutexLocker lockDatabase(m_databaseGuard);
218    SecurityOrigin* origin = context->securityOrigin();
219
220    // We have already eliminated other types of errors in canEstablishDatabase().
221    // The only reason we're in retryCanEstablishDatabase() is because we gave
222    // the client a chance to update the quota and are rechecking it here.
223    // If we fail this check, the only possible reason this time should be due
224    // to inadequate quota.
225    if (hasAdequateQuotaForOrigin(origin, estimatedSize, error)) {
226        ASSERT(error == DatabaseError::None);
227        return true;
228    }
229
230    ASSERT(error == DatabaseError::DatabaseSizeExceededQuota);
231    doneCreatingDatabase(origin, name);
232
233    return false;
234}
235
236bool DatabaseTracker::hasEntryForOriginNoLock(SecurityOrigin* origin)
237{
238    ASSERT(!m_databaseGuard.tryLock());
239    openTrackerDatabase(DontCreateIfDoesNotExist);
240    if (!m_database.isOpen())
241        return false;
242
243    SQLiteStatement statement(m_database, "SELECT origin FROM Origins where origin=?;");
244    if (statement.prepare() != SQLResultOk) {
245        LOG_ERROR("Failed to prepare statement.");
246        return false;
247    }
248
249    statement.bindText(1, origin->databaseIdentifier());
250
251    return statement.step() == SQLResultRow;
252}
253
254bool DatabaseTracker::hasEntryForOrigin(SecurityOrigin* origin)
255{
256    MutexLocker lockDatabase(m_databaseGuard);
257    return hasEntryForOriginNoLock(origin);
258}
259
260bool DatabaseTracker::hasEntryForDatabase(SecurityOrigin* origin, const String& databaseIdentifier)
261{
262    ASSERT(!m_databaseGuard.tryLock());
263    openTrackerDatabase(DontCreateIfDoesNotExist);
264    if (!m_database.isOpen()) {
265        // No "tracker database". Hence, no entry for the database of interest.
266        return false;
267    }
268
269    // We've got a tracker database. Set up a query to ask for the db of interest:
270    SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE origin=? AND name=?;");
271
272    if (statement.prepare() != SQLResultOk)
273        return false;
274
275    statement.bindText(1, origin->databaseIdentifier());
276    statement.bindText(2, databaseIdentifier);
277
278    return statement.step() == SQLResultRow;
279}
280
281unsigned long long DatabaseTracker::getMaxSizeForDatabase(const DatabaseBackendBase* database)
282{
283    // The maximum size for a database is the full quota for its origin, minus the current usage within the origin,
284    // plus the current usage of the given database
285    MutexLocker lockDatabase(m_databaseGuard);
286    SecurityOrigin* origin = database->securityOrigin();
287
288    unsigned long long quota = quotaForOriginNoLock(origin);
289    unsigned long long diskUsage = usageForOrigin(origin);
290    unsigned long long databaseFileSize = SQLiteFileSystem::getDatabaseFileSize(database->fileName());
291    ASSERT(databaseFileSize <= diskUsage);
292
293    if (diskUsage > quota)
294        return databaseFileSize;
295
296    // A previous error may have allowed the origin to exceed its quota, or may
297    // have allowed this database to exceed our cached estimate of the origin
298    // disk usage. Don't multiply that error through integer underflow, or the
299    // effective quota will permanently become 2^64.
300    unsigned long long maxSize = quota - diskUsage + databaseFileSize;
301    if (maxSize > quota)
302        maxSize = databaseFileSize;
303    return maxSize;
304}
305
306void DatabaseTracker::interruptAllDatabasesForContext(const DatabaseBackendContext* context)
307{
308    Vector<RefPtr<DatabaseBackendBase>> openDatabases;
309    {
310        MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
311
312        if (!m_openDatabaseMap)
313            return;
314
315        DatabaseNameMap* nameMap = m_openDatabaseMap->get(context->securityOrigin());
316        if (!nameMap)
317            return;
318
319        DatabaseNameMap::const_iterator dbNameMapEndIt = nameMap->end();
320        for (DatabaseNameMap::const_iterator dbNameMapIt = nameMap->begin(); dbNameMapIt != dbNameMapEndIt; ++dbNameMapIt) {
321            DatabaseSet* databaseSet = dbNameMapIt->value;
322            DatabaseSet::const_iterator dbSetEndIt = databaseSet->end();
323            for (DatabaseSet::const_iterator dbSetIt = databaseSet->begin(); dbSetIt != dbSetEndIt; ++dbSetIt) {
324                if ((*dbSetIt)->databaseContext() == context)
325                    openDatabases.append(*dbSetIt);
326            }
327        }
328    }
329
330    Vector<RefPtr<DatabaseBackendBase>>::const_iterator openDatabasesEndIt = openDatabases.end();
331    for (Vector<RefPtr<DatabaseBackendBase>>::const_iterator openDatabasesIt = openDatabases.begin(); openDatabasesIt != openDatabasesEndIt; ++openDatabasesIt)
332        (*openDatabasesIt)->interrupt();
333}
334
335String DatabaseTracker::originPath(SecurityOrigin* origin) const
336{
337    return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath.isolatedCopy(), origin->databaseIdentifier());
338}
339
340String DatabaseTracker::fullPathForDatabaseNoLock(SecurityOrigin* origin, const String& name, bool createIfNotExists)
341{
342    ASSERT(!m_databaseGuard.tryLock());
343
344    String originIdentifier = origin->databaseIdentifier();
345    String originPath = this->originPath(origin);
346
347    // Make sure the path for this SecurityOrigin exists
348    if (createIfNotExists && !SQLiteFileSystem::ensureDatabaseDirectoryExists(originPath))
349        return String();
350
351    // See if we have a path for this database yet
352    if (!m_database.isOpen())
353        return String();
354    SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE origin=? AND name=?;");
355
356    if (statement.prepare() != SQLResultOk)
357        return String();
358
359    statement.bindText(1, originIdentifier);
360    statement.bindText(2, name);
361
362    int result = statement.step();
363
364    if (result == SQLResultRow)
365        return SQLiteFileSystem::appendDatabaseFileNameToPath(originPath, statement.getColumnText(0));
366    if (!createIfNotExists)
367        return String();
368
369    if (result != SQLResultDone) {
370        LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", originIdentifier.ascii().data(), name.ascii().data());
371        return String();
372    }
373    statement.finalize();
374
375    String fileName = SQLiteFileSystem::getFileNameForNewDatabase(originPath, name, originIdentifier, &m_database);
376    if (!addDatabase(origin, name, fileName))
377        return String();
378
379    // If this origin's quota is being tracked (open handle to a database in this origin), add this new database
380    // to the quota manager now
381    String fullFilePath = SQLiteFileSystem::appendDatabaseFileNameToPath(originPath, fileName);
382
383    return fullFilePath;
384}
385
386String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool createIfNotExists)
387{
388    MutexLocker lockDatabase(m_databaseGuard);
389    return fullPathForDatabaseNoLock(origin, name, createIfNotExists).isolatedCopy();
390}
391
392void DatabaseTracker::origins(Vector<RefPtr<SecurityOrigin>>& originsResult)
393{
394    MutexLocker lockDatabase(m_databaseGuard);
395
396    openTrackerDatabase(DontCreateIfDoesNotExist);
397    if (!m_database.isOpen())
398        return;
399
400    SQLiteStatement statement(m_database, "SELECT origin FROM Origins");
401    if (statement.prepare() != SQLResultOk) {
402        LOG_ERROR("Failed to prepare statement.");
403        return;
404    }
405
406    int result;
407    while ((result = statement.step()) == SQLResultRow) {
408        RefPtr<SecurityOrigin> origin = SecurityOrigin::createFromDatabaseIdentifier(statement.getColumnText(0));
409        originsResult.append(origin->isolatedCopy());
410    }
411    originsResult.shrinkToFit();
412
413    if (result != SQLResultDone)
414        LOG_ERROR("Failed to read in all origins from the database.");
415}
416
417bool DatabaseTracker::databaseNamesForOriginNoLock(SecurityOrigin* origin, Vector<String>& resultVector)
418{
419    ASSERT(!m_databaseGuard.tryLock());
420    openTrackerDatabase(DontCreateIfDoesNotExist);
421    if (!m_database.isOpen())
422        return false;
423
424    SQLiteStatement statement(m_database, "SELECT name FROM Databases where origin=?;");
425
426    if (statement.prepare() != SQLResultOk)
427        return false;
428
429    statement.bindText(1, origin->databaseIdentifier());
430
431    int result;
432    while ((result = statement.step()) == SQLResultRow)
433        resultVector.append(statement.getColumnText(0));
434
435    if (result != SQLResultDone) {
436        LOG_ERROR("Failed to retrieve all database names for origin %s", origin->databaseIdentifier().ascii().data());
437        return false;
438    }
439
440    return true;
441}
442
443bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<String>& resultVector)
444{
445    Vector<String> temp;
446    {
447        MutexLocker lockDatabase(m_databaseGuard);
448        if (!databaseNamesForOriginNoLock(origin, temp))
449          return false;
450    }
451
452    for (Vector<String>::iterator iter = temp.begin(); iter != temp.end(); ++iter)
453        resultVector.append(iter->isolatedCopy());
454    return true;
455}
456
457DatabaseDetails DatabaseTracker::detailsForNameAndOrigin(const String& name, SecurityOrigin* origin)
458{
459    String originIdentifier = origin->databaseIdentifier();
460    String displayName;
461    int64_t expectedUsage;
462
463    {
464        MutexLocker lockDatabase(m_databaseGuard);
465
466        openTrackerDatabase(DontCreateIfDoesNotExist);
467        if (!m_database.isOpen())
468            return DatabaseDetails();
469        SQLiteStatement statement(m_database, "SELECT displayName, estimatedSize FROM Databases WHERE origin=? AND name=?");
470        if (statement.prepare() != SQLResultOk)
471            return DatabaseDetails();
472
473        statement.bindText(1, originIdentifier);
474        statement.bindText(2, name);
475
476        int result = statement.step();
477        if (result == SQLResultDone)
478            return DatabaseDetails();
479
480        if (result != SQLResultRow) {
481            LOG_ERROR("Error retrieving details for database %s in origin %s from tracker database", name.ascii().data(), originIdentifier.ascii().data());
482            return DatabaseDetails();
483        }
484        displayName = statement.getColumnText(0);
485        expectedUsage = statement.getColumnInt64(1);
486    }
487
488    String path = fullPathForDatabase(origin, name, false);
489    if (path.isEmpty())
490        return DatabaseDetails(name, displayName, expectedUsage, 0, 0, 0);
491    return DatabaseDetails(name, displayName, expectedUsage, SQLiteFileSystem::getDatabaseFileSize(path), SQLiteFileSystem::databaseCreationTime(path), SQLiteFileSystem::databaseModificationTime(path));
492}
493
494void DatabaseTracker::setDatabaseDetails(SecurityOrigin* origin, const String& name, const String& displayName, unsigned long estimatedSize)
495{
496    String originIdentifier = origin->databaseIdentifier();
497    int64_t guid = 0;
498
499    MutexLocker lockDatabase(m_databaseGuard);
500
501    openTrackerDatabase(CreateIfDoesNotExist);
502    if (!m_database.isOpen())
503        return;
504    SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE origin=? AND name=?");
505    if (statement.prepare() != SQLResultOk)
506        return;
507
508    statement.bindText(1, originIdentifier);
509    statement.bindText(2, name);
510
511    int result = statement.step();
512    if (result == SQLResultRow)
513        guid = statement.getColumnInt64(0);
514    statement.finalize();
515
516    if (guid == 0) {
517        if (result != SQLResultDone)
518            LOG_ERROR("Error to determing existence of database %s in origin %s in tracker database", name.ascii().data(), originIdentifier.ascii().data());
519        else {
520            // This case should never occur - we should never be setting database details for a database that doesn't already exist in the tracker
521            // But since the tracker file is an external resource not under complete control of our code, it's somewhat invalid to make this an ASSERT case
522            // So we'll print an error instead
523            LOG_ERROR("Could not retrieve guid for database %s in origin %s from the tracker database - it is invalid to set database details on a database that doesn't already exist in the tracker",
524                       name.ascii().data(), originIdentifier.ascii().data());
525        }
526        return;
527    }
528
529    SQLiteStatement updateStatement(m_database, "UPDATE Databases SET displayName=?, estimatedSize=? WHERE guid=?");
530    if (updateStatement.prepare() != SQLResultOk)
531        return;
532
533    updateStatement.bindText(1, displayName);
534    updateStatement.bindInt64(2, estimatedSize);
535    updateStatement.bindInt64(3, guid);
536
537    if (updateStatement.step() != SQLResultDone) {
538        LOG_ERROR("Failed to update details for database %s in origin %s", name.ascii().data(), originIdentifier.ascii().data());
539        return;
540    }
541
542    if (m_client)
543        m_client->dispatchDidModifyDatabase(origin, name);
544}
545
546void DatabaseTracker::doneCreatingDatabase(DatabaseBackendBase* database)
547{
548    MutexLocker lockDatabase(m_databaseGuard);
549    doneCreatingDatabase(database->securityOrigin(), database->stringIdentifier());
550}
551
552void DatabaseTracker::addOpenDatabase(DatabaseBackendBase* database)
553{
554    if (!database)
555        return;
556
557    {
558        MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
559
560        if (!m_openDatabaseMap)
561            m_openDatabaseMap = std::make_unique<DatabaseOriginMap>();
562
563        String name(database->stringIdentifier());
564        DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin());
565        if (!nameMap) {
566            nameMap = new DatabaseNameMap;
567            m_openDatabaseMap->set(database->securityOrigin()->isolatedCopy(), nameMap);
568        }
569
570        DatabaseSet* databaseSet = nameMap->get(name);
571        if (!databaseSet) {
572            databaseSet = new DatabaseSet;
573            nameMap->set(name.isolatedCopy(), databaseSet);
574        }
575
576        databaseSet->add(database);
577
578        LOG(StorageAPI, "Added open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database);
579    }
580}
581
582void DatabaseTracker::removeOpenDatabase(DatabaseBackendBase* database)
583{
584    if (!database)
585        return;
586
587    {
588        MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
589
590        if (!m_openDatabaseMap) {
591            ASSERT_NOT_REACHED();
592            return;
593        }
594
595        String name(database->stringIdentifier());
596        DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin());
597        if (!nameMap) {
598            ASSERT_NOT_REACHED();
599            return;
600        }
601
602        DatabaseSet* databaseSet = nameMap->get(name);
603        if (!databaseSet) {
604            ASSERT_NOT_REACHED();
605            return;
606        }
607
608        databaseSet->remove(database);
609
610        LOG(StorageAPI, "Removed open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database);
611
612        if (!databaseSet->isEmpty())
613            return;
614
615        nameMap->remove(name);
616        delete databaseSet;
617
618        if (!nameMap->isEmpty())
619            return;
620
621        m_openDatabaseMap->remove(database->securityOrigin());
622        delete nameMap;
623    }
624}
625
626void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<DatabaseBackendBase>>* databases)
627{
628    MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
629    if (!m_openDatabaseMap)
630        return;
631
632    DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin);
633    if (!nameMap)
634        return;
635
636    DatabaseSet* databaseSet = nameMap->get(name);
637    if (!databaseSet)
638        return;
639
640    for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end(); ++it)
641        databases->add(*it);
642}
643
644PassRefPtr<OriginLock> DatabaseTracker::originLockFor(SecurityOrigin* origin)
645{
646    MutexLocker lockDatabase(m_databaseGuard);
647    String databaseIdentifier = origin->databaseIdentifier();
648
649    // The originLockMap is accessed from multiple DatabaseThreads since
650    // different script contexts can be writing to different databases from
651    // the same origin. Hence, the databaseIdentifier key needs to be an
652    // isolated copy. An isolated copy gives us a value whose refCounting is
653    // thread-safe, since our copy is guarded by the m_databaseGuard mutex.
654    databaseIdentifier = databaseIdentifier.isolatedCopy();
655
656    OriginLockMap::AddResult addResult =
657        m_originLockMap.add(databaseIdentifier, RefPtr<OriginLock>());
658    if (!addResult.isNewEntry)
659        return addResult.iterator->value;
660
661    String path = originPath(origin);
662    RefPtr<OriginLock> lock = adoptRef(new OriginLock(path));
663    ASSERT(lock);
664    addResult.iterator->value = lock;
665
666    return lock.release();
667}
668
669void DatabaseTracker::deleteOriginLockFor(SecurityOrigin* origin)
670{
671    ASSERT(!m_databaseGuard.tryLock());
672
673    // There is not always an instance of an OriginLock associated with an origin.
674    // For example, if the OriginLock lock file was created by a previous run of
675    // the browser which has now terminated, and the current browser process
676    // has not executed any database transactions from this origin that would
677    // have created the OriginLock instance in memory. In this case, we will have
678    // a lock file but not an OriginLock instance in memory.
679
680    // This function is only called if we are already deleting all the database
681    // files in this origin. We'll give the OriginLock one chance to do an
682    // orderly clean up first when we remove its ref from the m_originLockMap.
683    // This may or may not be possible depending on whether other threads are
684    // also using the OriginLock at the same time. After that, we will go ahead
685    // and delete the lock file.
686
687    m_originLockMap.remove(origin->databaseIdentifier());
688    OriginLock::deleteLockFile(originPath(origin));
689}
690
691unsigned long long DatabaseTracker::usageForOrigin(SecurityOrigin* origin)
692{
693    String originPath = this->originPath(origin);
694    unsigned long long diskUsage = 0;
695    Vector<String> fileNames = listDirectory(originPath, String("*.db"));
696    Vector<String>::iterator fileName = fileNames.begin();
697    Vector<String>::iterator lastFileName = fileNames.end();
698    for (; fileName != lastFileName; ++fileName) {
699        long long size;
700        getFileSize(*fileName, size);
701        diskUsage += size;
702    }
703    return diskUsage;
704}
705
706unsigned long long DatabaseTracker::quotaForOriginNoLock(SecurityOrigin* origin)
707{
708    ASSERT(!m_databaseGuard.tryLock());
709    unsigned long long quota = 0;
710
711    openTrackerDatabase(DontCreateIfDoesNotExist);
712    if (!m_database.isOpen())
713        return quota;
714
715    SQLiteStatement statement(m_database, "SELECT quota FROM Origins where origin=?;");
716    if (statement.prepare() != SQLResultOk) {
717        LOG_ERROR("Failed to prepare statement.");
718        return quota;
719    }
720    statement.bindText(1, origin->databaseIdentifier());
721
722    if (statement.step() == SQLResultRow)
723        quota = statement.getColumnInt64(0);
724
725    return quota;
726}
727
728unsigned long long DatabaseTracker::quotaForOrigin(SecurityOrigin* origin)
729{
730    MutexLocker lockDatabase(m_databaseGuard);
731    return quotaForOriginNoLock(origin);
732}
733
734void DatabaseTracker::setQuota(SecurityOrigin* origin, unsigned long long quota)
735{
736    MutexLocker lockDatabase(m_databaseGuard);
737
738    if (quotaForOriginNoLock(origin) == quota)
739        return;
740
741    openTrackerDatabase(CreateIfDoesNotExist);
742    if (!m_database.isOpen())
743        return;
744
745#if PLATFORM(IOS)
746    bool insertedNewOrigin = false;
747#endif
748
749    bool originEntryExists = hasEntryForOriginNoLock(origin);
750    if (!originEntryExists) {
751        SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)");
752        if (statement.prepare() != SQLResultOk) {
753            LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
754        } else {
755            statement.bindText(1, origin->databaseIdentifier());
756            statement.bindInt64(2, quota);
757
758            if (statement.step() != SQLResultDone)
759                LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
760#if PLATFORM(IOS)
761            else
762                insertedNewOrigin = true;
763#endif
764        }
765    } else {
766        SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");
767        bool error = statement.prepare() != SQLResultOk;
768        if (!error) {
769            statement.bindInt64(1, quota);
770            statement.bindText(2, origin->databaseIdentifier());
771
772            error = !statement.executeCommand();
773        }
774
775        if (error)
776            LOG_ERROR("Failed to set quota %llu in tracker database for origin %s", quota, origin->databaseIdentifier().ascii().data());
777    }
778
779    if (m_client)
780#if PLATFORM(IOS)
781    {
782        if (insertedNewOrigin)
783            m_client->dispatchDidAddNewOrigin(origin);
784#endif
785        m_client->dispatchDidModifyOrigin(origin);
786#if PLATFORM(IOS)
787    }
788#endif
789}
790
791bool DatabaseTracker::addDatabase(SecurityOrigin* origin, const String& name, const String& path)
792{
793    ASSERT(!m_databaseGuard.tryLock());
794    openTrackerDatabase(CreateIfDoesNotExist);
795    if (!m_database.isOpen())
796        return false;
797
798    // New database should never be added until the origin has been established
799    ASSERT(hasEntryForOriginNoLock(origin));
800
801    SQLiteStatement statement(m_database, "INSERT INTO Databases (origin, name, path) VALUES (?, ?, ?);");
802
803    if (statement.prepare() != SQLResultOk)
804        return false;
805
806    statement.bindText(1, origin->databaseIdentifier());
807    statement.bindText(2, name);
808    statement.bindText(3, path);
809
810    if (!statement.executeCommand()) {
811        LOG_ERROR("Failed to add database %s to origin %s: %s\n", name.ascii().data(), origin->databaseIdentifier().ascii().data(), m_database.lastErrorMsg());
812        return false;
813    }
814
815    if (m_client)
816        m_client->dispatchDidModifyOrigin(origin);
817
818    return true;
819}
820
821void DatabaseTracker::deleteAllDatabases()
822{
823    Vector<RefPtr<SecurityOrigin>> originsCopy;
824    origins(originsCopy);
825
826    for (unsigned i = 0; i < originsCopy.size(); ++i)
827        deleteOrigin(originsCopy[i].get());
828}
829
830// It is the caller's responsibility to make sure that nobody is trying to create, delete, open, or close databases in this origin while the deletion is
831// taking place.
832bool DatabaseTracker::deleteOrigin(SecurityOrigin* origin)
833{
834    Vector<String> databaseNames;
835    {
836        MutexLocker lockDatabase(m_databaseGuard);
837        openTrackerDatabase(DontCreateIfDoesNotExist);
838        if (!m_database.isOpen())
839            return false;
840
841        if (!databaseNamesForOriginNoLock(origin, databaseNames)) {
842            LOG_ERROR("Unable to retrieve list of database names for origin %s", origin->databaseIdentifier().ascii().data());
843            return false;
844        }
845        if (!canDeleteOrigin(origin)) {
846            LOG_ERROR("Tried to delete an origin (%s) while either creating database in it or already deleting it", origin->databaseIdentifier().ascii().data());
847            ASSERT_NOT_REACHED();
848            return false;
849        }
850        recordDeletingOrigin(origin);
851    }
852
853    // We drop the lock here because holding locks during a call to deleteDatabaseFile will deadlock.
854    for (unsigned i = 0; i < databaseNames.size(); ++i) {
855        if (!deleteDatabaseFile(origin, databaseNames[i])) {
856            // Even if the file can't be deleted, we want to try and delete the rest, don't return early here.
857            LOG_ERROR("Unable to delete file for database %s in origin %s", databaseNames[i].ascii().data(), origin->databaseIdentifier().ascii().data());
858        }
859    }
860
861    {
862        MutexLocker lockDatabase(m_databaseGuard);
863        deleteOriginLockFor(origin);
864        doneDeletingOrigin(origin);
865
866        SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?");
867        if (statement.prepare() != SQLResultOk) {
868            LOG_ERROR("Unable to prepare deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
869            return false;
870        }
871
872        statement.bindText(1, origin->databaseIdentifier());
873
874        if (!statement.executeCommand()) {
875            LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
876            return false;
877        }
878
879        SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE origin=?");
880        if (originStatement.prepare() != SQLResultOk) {
881            LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin->databaseIdentifier().ascii().data());
882            return false;
883        }
884
885        originStatement.bindText(1, origin->databaseIdentifier());
886
887        if (!originStatement.executeCommand()) {
888            LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
889            return false;
890        }
891
892        SQLiteFileSystem::deleteEmptyDatabaseDirectory(originPath(origin));
893
894        RefPtr<SecurityOrigin> originPossiblyLastReference = origin;
895        bool isEmpty = true;
896
897        openTrackerDatabase(DontCreateIfDoesNotExist);
898        if (m_database.isOpen()) {
899            SQLiteStatement statement(m_database, "SELECT origin FROM Origins");
900            if (statement.prepare() != SQLResultOk)
901                LOG_ERROR("Failed to prepare statement.");
902            else if (statement.step() == SQLResultRow)
903                isEmpty = false;
904        }
905
906        // If we removed the last origin, do some additional deletion.
907        if (isEmpty) {
908            if (m_database.isOpen())
909                m_database.close();
910           SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath());
911           SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_databaseDirectoryPath);
912        }
913
914        if (m_client) {
915            m_client->dispatchDidModifyOrigin(origin);
916#if PLATFORM(IOS)
917            m_client->dispatchDidDeleteDatabaseOrigin();
918#endif
919            for (unsigned i = 0; i < databaseNames.size(); ++i)
920                m_client->dispatchDidModifyDatabase(origin, databaseNames[i]);
921        }
922    }
923    return true;
924}
925
926bool DatabaseTracker::isDeletingDatabaseOrOriginFor(SecurityOrigin *origin, const String& name)
927{
928    ASSERT(!m_databaseGuard.tryLock());
929    // Can't create a database while someone else is deleting it; there's a risk of leaving untracked database debris on the disk.
930    return isDeletingDatabase(origin, name) || isDeletingOrigin(origin);
931}
932
933void DatabaseTracker::recordCreatingDatabase(SecurityOrigin *origin, const String& name)
934{
935    ASSERT(!m_databaseGuard.tryLock());
936    NameCountMap* nameMap = m_beingCreated.get(origin);
937    if (!nameMap) {
938        nameMap = new NameCountMap();
939        m_beingCreated.set(origin->isolatedCopy(), nameMap);
940    }
941    long count = nameMap->get(name);
942    nameMap->set(name.isolatedCopy(), count + 1);
943}
944
945void DatabaseTracker::doneCreatingDatabase(SecurityOrigin *origin, const String& name)
946{
947    ASSERT(!m_databaseGuard.tryLock());
948    NameCountMap* nameMap = m_beingCreated.get(origin);
949    ASSERT(nameMap);
950    if (!nameMap)
951        return;
952
953    long count = nameMap->get(name);
954    ASSERT(count > 0);
955    if (count <= 1) {
956        nameMap->remove(name);
957        if (nameMap->isEmpty()) {
958            m_beingCreated.remove(origin);
959            delete nameMap;
960        }
961    } else
962        nameMap->set(name, count - 1);
963}
964
965bool DatabaseTracker::creatingDatabase(SecurityOrigin *origin, const String& name)
966{
967    ASSERT(!m_databaseGuard.tryLock());
968    NameCountMap* nameMap = m_beingCreated.get(origin);
969    return nameMap && nameMap->get(name);
970}
971
972bool DatabaseTracker::canDeleteDatabase(SecurityOrigin *origin, const String& name)
973{
974    ASSERT(!m_databaseGuard.tryLock());
975    return !creatingDatabase(origin, name) && !isDeletingDatabase(origin, name);
976}
977
978void DatabaseTracker::recordDeletingDatabase(SecurityOrigin *origin, const String& name)
979{
980    ASSERT(!m_databaseGuard.tryLock());
981    ASSERT(canDeleteDatabase(origin, name));
982    NameSet* nameSet = m_beingDeleted.get(origin);
983    if (!nameSet) {
984        nameSet = new NameSet();
985        m_beingDeleted.set(origin->isolatedCopy(), nameSet);
986    }
987    ASSERT(!nameSet->contains(name));
988    nameSet->add(name.isolatedCopy());
989}
990
991void DatabaseTracker::doneDeletingDatabase(SecurityOrigin *origin, const String& name)
992{
993    ASSERT(!m_databaseGuard.tryLock());
994    NameSet* nameSet = m_beingDeleted.get(origin);
995    ASSERT(nameSet);
996    if (!nameSet)
997        return;
998
999    ASSERT(nameSet->contains(name));
1000    nameSet->remove(name);
1001    if (nameSet->isEmpty()) {
1002        m_beingDeleted.remove(origin);
1003        delete nameSet;
1004    }
1005}
1006
1007bool DatabaseTracker::isDeletingDatabase(SecurityOrigin *origin, const String& name)
1008{
1009    ASSERT(!m_databaseGuard.tryLock());
1010    NameSet* nameSet = m_beingDeleted.get(origin);
1011    return nameSet && nameSet->contains(name);
1012}
1013
1014bool DatabaseTracker::canDeleteOrigin(SecurityOrigin *origin)
1015{
1016    ASSERT(!m_databaseGuard.tryLock());
1017    return !(isDeletingOrigin(origin) || m_beingCreated.get(origin));
1018}
1019
1020bool DatabaseTracker::isDeletingOrigin(SecurityOrigin *origin)
1021{
1022    ASSERT(!m_databaseGuard.tryLock());
1023    return m_originsBeingDeleted.contains(origin);
1024}
1025
1026void DatabaseTracker::recordDeletingOrigin(SecurityOrigin *origin)
1027{
1028    ASSERT(!m_databaseGuard.tryLock());
1029    ASSERT(!isDeletingOrigin(origin));
1030    m_originsBeingDeleted.add(origin->isolatedCopy());
1031}
1032
1033void DatabaseTracker::doneDeletingOrigin(SecurityOrigin *origin)
1034{
1035    ASSERT(!m_databaseGuard.tryLock());
1036    ASSERT(isDeletingOrigin(origin));
1037    m_originsBeingDeleted.remove(origin);
1038}
1039
1040bool DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name)
1041{
1042    {
1043        MutexLocker lockDatabase(m_databaseGuard);
1044        openTrackerDatabase(DontCreateIfDoesNotExist);
1045        if (!m_database.isOpen())
1046            return false;
1047
1048        if (!canDeleteDatabase(origin, name)) {
1049            ASSERT_NOT_REACHED();
1050            return false;
1051        }
1052        recordDeletingDatabase(origin, name);
1053    }
1054
1055    // We drop the lock here because holding locks during a call to deleteDatabaseFile will deadlock.
1056    if (!deleteDatabaseFile(origin, name)) {
1057        LOG_ERROR("Unable to delete file for database %s in origin %s", name.ascii().data(), origin->databaseIdentifier().ascii().data());
1058        MutexLocker lockDatabase(m_databaseGuard);
1059        doneDeletingDatabase(origin, name);
1060        return false;
1061    }
1062
1063    MutexLocker lockDatabase(m_databaseGuard);
1064
1065    SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=? AND name=?");
1066    if (statement.prepare() != SQLResultOk) {
1067        LOG_ERROR("Unable to prepare deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data());
1068        doneDeletingDatabase(origin, name);
1069        return false;
1070    }
1071
1072    statement.bindText(1, origin->databaseIdentifier());
1073    statement.bindText(2, name);
1074
1075    if (!statement.executeCommand()) {
1076        LOG_ERROR("Unable to execute deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data());
1077        doneDeletingDatabase(origin, name);
1078        return false;
1079    }
1080
1081    if (m_client) {
1082        m_client->dispatchDidModifyOrigin(origin);
1083        m_client->dispatchDidModifyDatabase(origin, name);
1084#if PLATFORM(IOS)
1085        m_client->dispatchDidDeleteDatabase();
1086#endif
1087    }
1088    doneDeletingDatabase(origin, name);
1089
1090    return true;
1091}
1092
1093// deleteDatabaseFile has to release locks between looking up the list of databases to close and closing them.  While this is in progress, the caller
1094// is responsible for making sure no new databases are opened in the file to be deleted.
1095bool DatabaseTracker::deleteDatabaseFile(SecurityOrigin* origin, const String& name)
1096{
1097    String fullPath = fullPathForDatabase(origin, name, false);
1098    if (fullPath.isEmpty())
1099        return true;
1100
1101#ifndef NDEBUG
1102    {
1103        MutexLocker lockDatabase(m_databaseGuard);
1104        ASSERT(isDeletingDatabaseOrOriginFor(origin, name));
1105    }
1106#endif
1107
1108    Vector<RefPtr<DatabaseBackendBase>> deletedDatabases;
1109
1110    // Make sure not to hold the any locks when calling
1111    // Database::markAsDeletedAndClose(), since that can cause a deadlock
1112    // during the synchronous DatabaseThread call it triggers.
1113    {
1114        MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
1115        if (m_openDatabaseMap) {
1116            // There are some open databases, lets check if they are for this origin.
1117            DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin);
1118            if (nameMap && nameMap->size()) {
1119                // There are some open databases for this origin, let's check
1120                // if they are this database by name.
1121                DatabaseSet* databaseSet = nameMap->get(name);
1122                if (databaseSet && databaseSet->size()) {
1123                    // We have some database open with this name. Mark them as deleted.
1124                    DatabaseSet::const_iterator end = databaseSet->end();
1125                    for (DatabaseSet::const_iterator it = databaseSet->begin(); it != end; ++it)
1126                        deletedDatabases.append(*it);
1127                }
1128            }
1129        }
1130    }
1131
1132    for (unsigned i = 0; i < deletedDatabases.size(); ++i)
1133        deletedDatabases[i]->markAsDeletedAndClose();
1134
1135#if !PLATFORM(IOS)
1136    return SQLiteFileSystem::deleteDatabaseFile(fullPath);
1137#else
1138    // On the phone, other background processes may still be accessing this database.  Deleting the database directly
1139    // would nuke the POSIX file locks, potentially causing Safari/WebApp to corrupt the new db if it's running in the background.
1140    // We'll instead truncate the database file to 0 bytes.  If another process is operating on this same database file after
1141    // the truncation, it should get an error since the database file is no longer valid.  When Safari is launched
1142    // next time, it'll go through the database files and clean up any zero-bytes ones.
1143    SQLiteDatabase database;
1144    if (database.open(fullPath))
1145        return SQLiteFileSystem::truncateDatabaseFile(database.sqlite3Handle());
1146    return false;
1147#endif
1148}
1149
1150#if PLATFORM(IOS)
1151void DatabaseTracker::removeDeletedOpenedDatabases()
1152{
1153    // This is called when another app has deleted a database.  Go through all opened databases in this
1154    // tracker and close any that's no longer being tracked in the database.
1155
1156    {
1157        // Acquire the lock before calling openTrackerDatabase.
1158        MutexLocker lockDatabase(m_databaseGuard);
1159        openTrackerDatabase(DontCreateIfDoesNotExist);
1160    }
1161
1162    if (!m_database.isOpen())
1163        return;
1164
1165    // Keep track of which opened databases have been deleted.
1166    Vector<RefPtr<Database> > deletedDatabases;
1167    typedef HashMap<RefPtr<SecurityOrigin>, Vector<String> > DeletedDatabaseMap;
1168    DeletedDatabaseMap deletedDatabaseMap;
1169
1170    // Make sure not to hold the m_openDatabaseMapGuard mutex when calling
1171    // Database::markAsDeletedAndClose(), since that can cause a deadlock
1172    // during the synchronous DatabaseThread call it triggers.
1173    {
1174        MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
1175        if (m_openDatabaseMap) {
1176            DatabaseOriginMap::const_iterator originMapEnd = m_openDatabaseMap->end();
1177            for (DatabaseOriginMap::const_iterator originMapIt = m_openDatabaseMap->begin(); originMapIt != originMapEnd; ++originMapIt) {
1178                RefPtr<SecurityOrigin> origin = originMapIt->key;
1179                DatabaseNameMap* databaseNameMap = originMapIt->value;
1180                Vector<String> deletedDatabaseNamesForThisOrigin;
1181
1182                // Loop through all opened databases in this origin.  Get the current database file path of each database and see if
1183                // it still matches the path stored in the opened database object.
1184                DatabaseNameMap::const_iterator dbNameMapEnd = databaseNameMap->end();
1185                for (DatabaseNameMap::const_iterator dbNameMapIt = databaseNameMap->begin(); dbNameMapIt != dbNameMapEnd; ++dbNameMapIt) {
1186                    String databaseName = dbNameMapIt->key;
1187                    String databaseFileName;
1188                    SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE origin=? AND name=?;");
1189                    if (statement.prepare() == SQLResultOk) {
1190                        statement.bindText(1, origin->databaseIdentifier());
1191                        statement.bindText(2, databaseName);
1192                        if (statement.step() == SQLResultRow)
1193                            databaseFileName = statement.getColumnText(0);
1194                        statement.finalize();
1195                    }
1196
1197                    bool foundDeletedDatabase = false;
1198                    DatabaseSet* databaseSet = dbNameMapIt->value;
1199                    DatabaseSet::const_iterator dbEnd = databaseSet->end();
1200                    for (DatabaseSet::const_iterator dbIt = databaseSet->begin(); dbIt != dbEnd; ++dbIt) {
1201                        Database* db = static_cast<Database*>(*dbIt);
1202
1203                        // We are done if this database has already been marked as deleted.
1204                        if (db->deleted())
1205                            continue;
1206
1207                        // If this database has been deleted or if its database file no longer matches the current version, this database is no longer valid and it should be marked as deleted.
1208                        if (databaseFileName.isNull() || databaseFileName != pathGetFileName(db->fileName())) {
1209                            deletedDatabases.append(db);
1210                            foundDeletedDatabase = true;
1211                        }
1212                    }
1213
1214                    // If the database no longer exists, we should remember to remove it from the OriginQuotaManager later.
1215                    if (foundDeletedDatabase && databaseFileName.isNull())
1216                        deletedDatabaseNamesForThisOrigin.append(databaseName);
1217                }
1218
1219                if (!deletedDatabaseNamesForThisOrigin.isEmpty())
1220                    deletedDatabaseMap.set(origin, deletedDatabaseNamesForThisOrigin);
1221            }
1222        }
1223    }
1224
1225    for (unsigned i = 0; i < deletedDatabases.size(); ++i)
1226        deletedDatabases[i]->markAsDeletedAndClose();
1227
1228    DeletedDatabaseMap::const_iterator end = deletedDatabaseMap.end();
1229    for (DeletedDatabaseMap::const_iterator it = deletedDatabaseMap.begin(); it != end; ++it) {
1230        SecurityOrigin* origin = it->key.get();
1231        if (m_client)
1232            m_client->dispatchDidModifyOrigin(origin);
1233
1234        const Vector<String>& databaseNames = it->value;
1235        for (unsigned i = 0; i < databaseNames.size(); ++i) {
1236            if (m_client)
1237                m_client->dispatchDidModifyDatabase(origin, databaseNames[i]);
1238        }
1239    }
1240}
1241
1242static bool isZeroByteFile(const String& path)
1243{
1244    long long size = 0;
1245    return getFileSize(path, size) && !size;
1246}
1247
1248bool DatabaseTracker::deleteDatabaseFileIfEmpty(const String& path)
1249{
1250    if (!isZeroByteFile(path))
1251        return false;
1252
1253    SQLiteDatabase database;
1254    if (!database.open(path))
1255        return false;
1256
1257    // Specify that we want the exclusive locking mode, so after the next read,
1258    // we'll be holding the lock to this database file.
1259    SQLiteStatement lockStatement(database, "PRAGMA locking_mode=EXCLUSIVE;");
1260    if (lockStatement.prepare() != SQLResultOk)
1261        return false;
1262    int result = lockStatement.step();
1263    if (result != SQLResultRow && result != SQLResultDone)
1264        return false;
1265    lockStatement.finalize();
1266
1267    // Every sqlite database has a sqlite_master table that contains the schema for the database.
1268    // http://www.sqlite.org/faq.html#q7
1269    SQLiteStatement readStatement(database, "SELECT * FROM sqlite_master LIMIT 1;");
1270    if (readStatement.prepare() != SQLResultOk)
1271        return false;
1272    // We shouldn't expect any result.
1273    if (readStatement.step() != SQLResultDone)
1274        return false;
1275    readStatement.finalize();
1276
1277    // At this point, we hold the exclusive lock to this file.  Double-check again to make sure
1278    // it's still zero bytes.
1279    if (!isZeroByteFile(path))
1280        return false;
1281
1282    return SQLiteFileSystem::deleteDatabaseFile(path);
1283}
1284
1285Mutex& DatabaseTracker::openDatabaseMutex()
1286{
1287    static NeverDestroyed<Mutex> mutex;
1288    return mutex;
1289}
1290
1291void DatabaseTracker::emptyDatabaseFilesRemovalTaskWillBeScheduled()
1292{
1293    // Lock the database from opening any database until we are done with scanning the file system for
1294    // zero byte database files to remove.
1295    openDatabaseMutex().lock();
1296}
1297
1298void DatabaseTracker::emptyDatabaseFilesRemovalTaskDidFinish()
1299{
1300    openDatabaseMutex().unlock();
1301}
1302
1303void DatabaseTracker::setDatabasesPaused(bool paused)
1304{
1305    MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
1306    if (!m_openDatabaseMap)
1307        return;
1308
1309    // This walking is - sadly - the only reliable way to get at each open database thread.
1310    // This will be cleaner once <rdar://problem/5680441> or some other DB thread consolidation takes place.
1311    DatabaseOriginMap::iterator i = m_openDatabaseMap.get()->begin();
1312    DatabaseOriginMap::iterator end = m_openDatabaseMap.get()->end();
1313
1314    for (; i != end; ++i) {
1315        DatabaseNameMap* databaseNameMap = i->value;
1316        DatabaseNameMap::iterator j = databaseNameMap->begin();
1317        DatabaseNameMap::iterator dbNameMapEnd = databaseNameMap->end();
1318        for (; j != dbNameMapEnd; ++j) {
1319            DatabaseSet* databaseSet = j->value;
1320            DatabaseSet::iterator k = databaseSet->begin();
1321            DatabaseSet::iterator dbSetEnd = databaseSet->end();
1322            for (; k != dbSetEnd; ++k) {
1323                DatabaseContext* context = (*k)->databaseContext();
1324                context->setPaused(paused);
1325            }
1326        }
1327    }
1328}
1329
1330#endif
1331
1332void DatabaseTracker::setClient(DatabaseManagerClient* client)
1333{
1334    m_client = client;
1335}
1336
1337static Mutex& notificationMutex()
1338{
1339    static NeverDestroyed<Mutex> mutex;
1340    return mutex;
1341}
1342
1343typedef Vector<std::pair<RefPtr<SecurityOrigin>, String>> NotificationQueue;
1344
1345static NotificationQueue& notificationQueue()
1346{
1347    static NeverDestroyed<NotificationQueue> queue;
1348    return queue;
1349}
1350
1351void DatabaseTracker::scheduleNotifyDatabaseChanged(SecurityOrigin* origin, const String& name)
1352{
1353    MutexLocker locker(notificationMutex());
1354
1355    notificationQueue().append(std::pair<RefPtr<SecurityOrigin>, String>(origin->isolatedCopy(), name.isolatedCopy()));
1356    scheduleForNotification();
1357}
1358
1359static bool notificationScheduled = false;
1360
1361void DatabaseTracker::scheduleForNotification()
1362{
1363    ASSERT(!notificationMutex().tryLock());
1364
1365    if (!notificationScheduled) {
1366        callOnMainThread(DatabaseTracker::notifyDatabasesChanged, 0);
1367        notificationScheduled = true;
1368    }
1369}
1370
1371void DatabaseTracker::notifyDatabasesChanged(void*)
1372{
1373    // Note that if DatabaseTracker ever becomes non-singleton, we'll have to amend this notification
1374    // mechanism to include which tracker the notification goes out on as well.
1375    DatabaseTracker& theTracker(tracker());
1376
1377    NotificationQueue notifications;
1378    {
1379        MutexLocker locker(notificationMutex());
1380
1381        notifications.swap(notificationQueue());
1382
1383        notificationScheduled = false;
1384    }
1385
1386    if (!theTracker.m_client)
1387        return;
1388
1389    for (unsigned i = 0; i < notifications.size(); ++i)
1390        theTracker.m_client->dispatchDidModifyDatabase(notifications[i].first.get(), notifications[i].second);
1391}
1392
1393
1394} // namespace WebCore
1395#endif
1396