bool DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name) { { LockHolder lockDatabase(m_databaseGuard); openTrackerDatabase(DontCreateIfDoesNotExist); if (!m_database.isOpen()) return false; if (!canDeleteDatabase(origin, name)) { ASSERT_NOT_REACHED(); return false; } recordDeletingDatabase(origin, name); } // We drop the lock here because holding locks during a call to deleteDatabaseFile will deadlock. if (!deleteDatabaseFile(origin, name, DeletionMode::Default)) { LOG_ERROR("Unable to delete file for database %s in origin %s", name.ascii().data(), origin->databaseIdentifier().ascii().data()); LockHolder lockDatabase(m_databaseGuard); doneDeletingDatabase(origin, name); return false; } LockHolder lockDatabase(m_databaseGuard); SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=? AND name=?"); if (statement.prepare() != SQLITE_OK) { LOG_ERROR("Unable to prepare deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data()); doneDeletingDatabase(origin, name); return false; } statement.bindText(1, origin->databaseIdentifier()); statement.bindText(2, name); if (!statement.executeCommand()) { LOG_ERROR("Unable to execute deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data()); doneDeletingDatabase(origin, name); return false; } if (m_client) { m_client->dispatchDidModifyOrigin(origin); m_client->dispatchDidModifyDatabase(origin, name); #if PLATFORM(IOS) m_client->dispatchDidDeleteDatabase(); #endif } doneDeletingDatabase(origin, name); return true; }
// 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 // taking place. bool DatabaseTracker::deleteOrigin(SecurityOrigin* origin) { Vector<String> databaseNames; { MutexLocker lockDatabase(m_databaseGuard); openTrackerDatabase(DontCreateIfDoesNotExist); if (!m_database.isOpen()) return false; if (!databaseNamesForOriginNoLock(origin, databaseNames)) { LOG_ERROR("Unable to retrieve list of database names for origin %s", origin->databaseIdentifier().ascii().data()); return false; } if (!canDeleteOrigin(origin)) { LOG_ERROR("Tried to delete an origin (%s) while either creating database in it or already deleting it", origin->databaseIdentifier().ascii().data()); ASSERT_NOT_REACHED(); return false; } recordDeletingOrigin(origin); } // We drop the lock here because holding locks during a call to deleteDatabaseFile will deadlock. for (unsigned i = 0; i < databaseNames.size(); ++i) { if (!deleteDatabaseFile(origin, databaseNames[i])) { // Even if the file can't be deleted, we want to try and delete the rest, don't return early here. LOG_ERROR("Unable to delete file for database %s in origin %s", databaseNames[i].ascii().data(), origin->databaseIdentifier().ascii().data()); } } { MutexLocker lockDatabase(m_databaseGuard); deleteOriginLockFor(origin); doneDeletingOrigin(origin); SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?"); if (statement.prepare() != SQLResultOk) { LOG_ERROR("Unable to prepare deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data()); return false; } statement.bindText(1, origin->databaseIdentifier()); if (!statement.executeCommand()) { LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data()); return false; } SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE origin=?"); if (originStatement.prepare() != SQLResultOk) { LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin->databaseIdentifier().ascii().data()); return false; } originStatement.bindText(1, origin->databaseIdentifier()); if (!originStatement.executeCommand()) { LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data()); return false; } SQLiteFileSystem::deleteEmptyDatabaseDirectory(originPath(origin)); RefPtr<SecurityOrigin> originPossiblyLastReference = origin; bool isEmpty = true; openTrackerDatabase(DontCreateIfDoesNotExist); if (m_database.isOpen()) { SQLiteStatement statement(m_database, "SELECT origin FROM Origins"); if (statement.prepare() != SQLResultOk) LOG_ERROR("Failed to prepare statement."); else if (statement.step() == SQLResultRow) isEmpty = false; } // If we removed the last origin, do some additional deletion. if (isEmpty) { if (m_database.isOpen()) m_database.close(); SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath()); SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_databaseDirectoryPath); } if (m_client) { m_client->dispatchDidModifyOrigin(origin); for (unsigned i = 0; i < databaseNames.size(); ++i) m_client->dispatchDidModifyDatabase(origin, databaseNames[i]); } } return true; }