void StorageTracker::syncDeleteOrigin(const String& originIdentifier) { ASSERT(!isMainThread()); MutexLocker locker(m_databaseMutex); if (!canDeleteOrigin(originIdentifier)) { LOG_ERROR("Attempted to delete origin '%s' while it was being created\n", originIdentifier.ascii().data()); return; } openTrackerDatabase(false); if (!m_database.isOpen()) return; String path = databasePathForOrigin(originIdentifier); if (path.isEmpty()) { // It is possible to get a request from the API to delete the storage for an origin that // has no such storage. return; } SQLiteStatement deleteStatement(m_database, "DELETE FROM Origins where origin=?"); if (deleteStatement.prepare() != SQLResultOk) { LOG_ERROR("Unable to prepare deletion of origin '%s'", originIdentifier.ascii().data()); return; } deleteStatement.bindText(1, originIdentifier); if (!deleteStatement.executeCommand()) { LOG_ERROR("Unable to execute deletion of origin '%s'", originIdentifier.ascii().data()); return; } SQLiteFileSystem::deleteDatabaseFile(path); bool shouldDeleteTrackerFiles = false; { MutexLocker locker(m_originSetMutex); m_originSet.remove(originIdentifier); shouldDeleteTrackerFiles = m_originSet.isEmpty(); } if (shouldDeleteTrackerFiles) { m_database.close(); SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath()); SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_storageDirectoryPath); } { MutexLocker locker(m_clientMutex); if (m_client) m_client->dispatchDidModifyOrigin(originIdentifier); } }
void StorageTracker::syncDeleteAllOrigins() { ASSERT(!isMainThread()); MutexLocker locker(m_databaseMutex); openTrackerDatabase(false); if (!m_database.isOpen()) return; SQLiteStatement statement(m_database, "SELECT origin, path FROM Origins"); if (statement.prepare() != SQLResultOk) { LOG_ERROR("Failed to prepare statement."); return; } int result; while ((result = statement.step()) == SQLResultRow) { if (!canDeleteOrigin(statement.getColumnText(0))) continue; SQLiteFileSystem::deleteDatabaseFile(statement.getColumnText(1)); { MutexLocker locker(m_clientMutex); if (m_client) m_client->dispatchDidModifyOrigin(statement.getColumnText(0)); } } if (result != SQLResultDone) LOG_ERROR("Failed to read in all origins from the database."); if (m_database.isOpen()) m_database.close(); if (!SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath())) { // In the case where it is not possible to delete the database file (e.g some other program // like a virus scanner is accessing it), make sure to remove all entries. openTrackerDatabase(false); if (!m_database.isOpen()) return; SQLiteStatement deleteStatement(m_database, "DELETE FROM Origins"); if (deleteStatement.prepare() != SQLResultOk) { LOG_ERROR("Unable to prepare deletion of all origins"); return; } if (!deleteStatement.executeCommand()) { LOG_ERROR("Unable to execute deletion of all origins"); return; } } SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_storageDirectoryPath); }
// 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; }
void StorageTracker::syncDeleteAllOrigins() { ASSERT(!isMainThread()); SQLiteTransactionInProgressAutoCounter transactionCounter; LockHolder locker(m_databaseMutex); openTrackerDatabase(false); if (!m_database.isOpen()) return; SQLiteStatement statement(m_database, "SELECT origin, path FROM Origins"); if (statement.prepare() != SQLITE_OK) { LOG_ERROR("Failed to prepare statement."); return; } int result; while ((result = statement.step()) == SQLITE_ROW) { if (!canDeleteOrigin(statement.getColumnText(0))) continue; deleteFile(statement.getColumnText(1)); { LockHolder locker(m_clientMutex); if (m_client) m_client->dispatchDidModifyOrigin(statement.getColumnText(0)); } } if (result != SQLITE_DONE) LOG_ERROR("Failed to read in all origins from the database."); if (m_database.isOpen()) { #if PLATFORM(IOS) truncateDatabaseFile(m_database); #endif m_database.close(); } #if !PLATFORM(IOS) if (!deleteFile(trackerDatabasePath())) { // In the case where it is not possible to delete the database file (e.g some other program // like a virus scanner is accessing it), make sure to remove all entries. openTrackerDatabase(false); if (!m_database.isOpen()) return; SQLiteStatement deleteStatement(m_database, "DELETE FROM Origins"); if (deleteStatement.prepare() != SQLITE_OK) { LOG_ERROR("Unable to prepare deletion of all origins"); return; } if (!deleteStatement.executeCommand()) { LOG_ERROR("Unable to execute deletion of all origins"); return; } } deleteEmptyDirectory(m_storageDirectoryPath); #endif }
void StorageTracker::syncDeleteOrigin(const String& originIdentifier) { ASSERT(!isMainThread()); MutexLocker lockDatabase(m_databaseGuard); if (!canDeleteOrigin(originIdentifier)) { LOG_ERROR("Attempted to delete origin '%s' while it was being created\n", originIdentifier.ascii().data()); return; } openTrackerDatabase(false); if (!m_database.isOpen()) return; // Get origin's db file path, delete entry in tracker's db, then delete db file. SQLiteStatement pathStatement(m_database, "SELECT path FROM Origins WHERE origin=?"); if (pathStatement.prepare() != SQLResultOk) { LOG_ERROR("Unable to prepare selection of path for origin '%s'", originIdentifier.ascii().data()); return; } pathStatement.bindText(1, originIdentifier); int result = pathStatement.step(); if (result != SQLResultRow) { LOG_ERROR("Unable to find origin '%s' in Origins table", originIdentifier.ascii().data()); return; } String path = pathStatement.getColumnText(0); ASSERT(!path.isEmpty()); SQLiteStatement deleteStatement(m_database, "DELETE FROM Origins where origin=?"); if (deleteStatement.prepare() != SQLResultOk) { LOG_ERROR("Unable to prepare deletion of origin '%s'", originIdentifier.ascii().data()); return; } deleteStatement.bindText(1, originIdentifier); if (!deleteStatement.executeCommand()) { LOG_ERROR("Unable to execute deletion of origin '%s'", originIdentifier.ascii().data()); return; } SQLiteFileSystem::deleteDatabaseFile(path); bool shouldDeleteTrackerFiles = false; { MutexLocker originLock(m_originSetGuard); m_originSet.remove(originIdentifier); shouldDeleteTrackerFiles = m_originSet.isEmpty(); } if (shouldDeleteTrackerFiles) { m_database.close(); SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath()); SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_storageDirectoryPath); } { MutexLocker lockClient(m_clientGuard); if (m_client) m_client->dispatchDidModifyOrigin(originIdentifier); } }