diff --git a/api/net/sf/briar/api/db/DatabaseComponent.java b/api/net/sf/briar/api/db/DatabaseComponent.java
index 67ebdcd2b0b99d1b243327952239eab2e185c3ad..4f5f339a62ad60068839d257e0db2b1ecb2ad3b6 100644
--- a/api/net/sf/briar/api/db/DatabaseComponent.java
+++ b/api/net/sf/briar/api/db/DatabaseComponent.java
@@ -36,10 +36,10 @@ public interface DatabaseComponent {
 	 * @param resume True to reopen an existing database or false to create a
 	 * new one.
 	 */
-	void open(boolean resume) throws DbException;
+	void open(boolean resume) throws DbException, IOException;
 
 	/** Waits for any open transactions to finish and closes the database. */
-	void close() throws DbException;
+	void close() throws DbException, IOException;
 
 	/** Adds a listener to be notified when database events occur. */
 	void addListener(DatabaseListener d);
diff --git a/components/net/sf/briar/db/Database.java b/components/net/sf/briar/db/Database.java
index 560f38a3d429007bf09bb68c495e230ed213f1cb..55edbec1df03727dc776c800acb7562bec5ceb2a 100644
--- a/components/net/sf/briar/db/Database.java
+++ b/components/net/sf/briar/db/Database.java
@@ -1,5 +1,6 @@
 package net.sf.briar.db;
 
+import java.io.IOException;
 import java.util.Collection;
 import java.util.Map;
 
@@ -48,13 +49,13 @@ interface Database<T> {
 	 * @param resume True to reopen an existing database, false to create a
 	 * new one.
 	 */
-	void open(boolean resume) throws DbException;
+	void open(boolean resume) throws DbException, IOException;
 
 	/**
 	 * Prevents new transactions from starting, waits for all current
 	 * transactions to finish, and closes the database.
 	 */
-	void close() throws DbException;
+	void close() throws DbException, IOException;
 
 	/** Starts a new transaction and returns an object representing it. */
 	T startTransaction() throws DbException;
diff --git a/components/net/sf/briar/db/DatabaseComponentImpl.java b/components/net/sf/briar/db/DatabaseComponentImpl.java
index 33ba3e8325bb9609795d1c2dde670ea1a34a447f..2c6be4f61dbbd70bb86a02184483bfab7b3362d2 100644
--- a/components/net/sf/briar/db/DatabaseComponentImpl.java
+++ b/components/net/sf/briar/db/DatabaseComponentImpl.java
@@ -96,12 +96,12 @@ DatabaseCleaner.Callback {
 		this.cleaner = cleaner;
 	}
 
-	public void open(boolean resume) throws DbException {
+	public void open(boolean resume) throws DbException, IOException {
 		db.open(resume);
 		cleaner.startCleaning(this, MAX_MS_BETWEEN_SPACE_CHECKS);
 	}
 
-	public void close() throws DbException {
+	public void close() throws DbException, IOException {
 		cleaner.stopCleaning();
 		db.close();
 	}
diff --git a/components/net/sf/briar/db/H2Database.java b/components/net/sf/briar/db/H2Database.java
index 9bfcb69ebf1d7967ac8091df80015fcf4499e32b..b61172b65b2ba9133f19a0b71237949fd4cc650c 100644
--- a/components/net/sf/briar/db/H2Database.java
+++ b/components/net/sf/briar/db/H2Database.java
@@ -46,7 +46,7 @@ class H2Database extends JdbcDatabase {
 		this.maxSize = maxSize;
 	}
 
-	public void open(boolean resume) throws DbException {
+	public void open(boolean resume) throws DbException, IOException {
 		super.open(resume, home.getParentFile(), "org.h2.Driver");
 	}
 
diff --git a/components/net/sf/briar/db/JdbcDatabase.java b/components/net/sf/briar/db/JdbcDatabase.java
index 01ed4367886b8fe9a0be85257d9d53968b573490..537800e6ccebf2fae67ca4459e2f7e23f3d43d12 100644
--- a/components/net/sf/briar/db/JdbcDatabase.java
+++ b/components/net/sf/briar/db/JdbcDatabase.java
@@ -2,6 +2,7 @@ package net.sf.briar.db;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.IOException;
 import java.sql.Blob;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
@@ -242,7 +243,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 	}
 
 	protected void open(boolean resume, File dir, String driverClass)
-	throws DbException {
+	throws DbException, IOException {
 		if(resume) {
 			if(!dir.exists()) throw new DbException();
 			if(!dir.isDirectory()) throw new DbException();
diff --git a/test/net/sf/briar/db/DatabaseComponentTest.java b/test/net/sf/briar/db/DatabaseComponentTest.java
index 510b9737df5f6fd93c52fe7b92c846fe597925d2..f171ea5f938224e61de728184f14918d2454d708 100644
--- a/test/net/sf/briar/db/DatabaseComponentTest.java
+++ b/test/net/sf/briar/db/DatabaseComponentTest.java
@@ -14,7 +14,6 @@ import net.sf.briar.api.TransportId;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DatabaseListener;
 import net.sf.briar.api.db.DatabaseListener.Event;
-import net.sf.briar.api.db.DbException;
 import net.sf.briar.api.db.NoSuchContactException;
 import net.sf.briar.api.db.Status;
 import net.sf.briar.api.protocol.Ack;
@@ -84,7 +83,7 @@ public abstract class DatabaseComponentTest extends TestCase {
 			Database<T> database, DatabaseCleaner cleaner);
 
 	@Test
-	public void testSimpleCalls() throws DbException {
+	public void testSimpleCalls() throws Exception {
 		Mockery context = new Mockery();
 		@SuppressWarnings("unchecked")
 		final Database<Object> database = context.mock(Database.class);
@@ -187,7 +186,7 @@ public abstract class DatabaseComponentTest extends TestCase {
 	}
 
 	@Test
-	public void testNullParentStopsBackwardInclusion() throws DbException {
+	public void testNullParentStopsBackwardInclusion() throws Exception {
 		Mockery context = new Mockery();
 		@SuppressWarnings("unchecked")
 		final Database<Object> database = context.mock(Database.class);
@@ -216,8 +215,7 @@ public abstract class DatabaseComponentTest extends TestCase {
 	}
 
 	@Test
-	public void testUnaffectedParentStopsBackwardInclusion()
-	throws DbException {
+	public void testUnaffectedParentStopsBackwardInclusion() throws Exception {
 		Mockery context = new Mockery();
 		@SuppressWarnings("unchecked")
 		final Database<Object> database = context.mock(Database.class);
@@ -251,7 +249,7 @@ public abstract class DatabaseComponentTest extends TestCase {
 
 	@Test
 	public void testAffectedParentContinuesBackwardInclusion()
-	throws DbException {
+	throws Exception {
 		Mockery context = new Mockery();
 		@SuppressWarnings("unchecked")
 		final Database<Object> database = context.mock(Database.class);
@@ -288,7 +286,7 @@ public abstract class DatabaseComponentTest extends TestCase {
 
 	@Test
 	public void testGroupMessagesAreNotStoredUnlessSubscribed()
-	throws DbException {
+	throws Exception {
 		Mockery context = new Mockery();
 		@SuppressWarnings("unchecked")
 		final Database<Object> database = context.mock(Database.class);
@@ -309,7 +307,7 @@ public abstract class DatabaseComponentTest extends TestCase {
 	}
 
 	@Test
-	public void testDuplicateGroupMessagesAreNotStored() throws DbException {
+	public void testDuplicateGroupMessagesAreNotStored() throws Exception {
 		Mockery context = new Mockery();
 		@SuppressWarnings("unchecked")
 		final Database<Object> database = context.mock(Database.class);
@@ -332,7 +330,7 @@ public abstract class DatabaseComponentTest extends TestCase {
 	}
 
 	@Test
-	public void testAddLocalGroupMessage() throws DbException {
+	public void testAddLocalGroupMessage() throws Exception {
 		Mockery context = new Mockery();
 		@SuppressWarnings("unchecked")
 		final Database<Object> database = context.mock(Database.class);
@@ -365,7 +363,7 @@ public abstract class DatabaseComponentTest extends TestCase {
 
 	@Test
 	public void testAddingSendableMessageTriggersBackwardInclusion()
-	throws DbException {
+	throws Exception {
 		Mockery context = new Mockery();
 		@SuppressWarnings("unchecked")
 		final Database<Object> database = context.mock(Database.class);
@@ -400,7 +398,7 @@ public abstract class DatabaseComponentTest extends TestCase {
 	}
 
 	@Test
-	public void testDuplicatePrivateMessagesAreNotStored() throws DbException {
+	public void testDuplicatePrivateMessagesAreNotStored() throws Exception {
 		Mockery context = new Mockery();
 		@SuppressWarnings("unchecked")
 		final Database<Object> database = context.mock(Database.class);
@@ -423,7 +421,7 @@ public abstract class DatabaseComponentTest extends TestCase {
 	}
 
 	@Test
-	public void testAddLocalPrivateMessage() throws DbException {
+	public void testAddLocalPrivateMessage() throws Exception {
 		Mockery context = new Mockery();
 		@SuppressWarnings("unchecked")
 		final Database<Object> database = context.mock(Database.class);
@@ -464,9 +462,10 @@ public abstract class DatabaseComponentTest extends TestCase {
 		final Batch batch = context.mock(Batch.class);
 		final Offer offer = context.mock(Offer.class);
 		final RequestWriter requestWriter = context.mock(RequestWriter.class);
-		final SubscriptionUpdate subscriptionsUpdate =
+		final SubscriptionUpdate subscriptionUpdate =
 			context.mock(SubscriptionUpdate.class);
-		final TransportUpdate transportsUpdate = context.mock(TransportUpdate.class);
+		final TransportUpdate transportUpdate =
+			context.mock(TransportUpdate.class);
 		context.checking(new Expectations() {{
 			// Check whether the contact is still in the DB (which it's not)
 			exactly(18).of(database).startTransaction();
@@ -549,12 +548,12 @@ public abstract class DatabaseComponentTest extends TestCase {
 		} catch(NoSuchContactException expected) {}
 
 		try {
-			db.receiveSubscriptionUpdate(contactId, subscriptionsUpdate);
+			db.receiveSubscriptionUpdate(contactId, subscriptionUpdate);
 			fail();
 		} catch(NoSuchContactException expected) {}
 
 		try {
-			db.receiveTransportUpdate(contactId, transportsUpdate);
+			db.receiveTransportUpdate(contactId, transportUpdate);
 			fail();
 		} catch(NoSuchContactException expected) {}
 
diff --git a/test/net/sf/briar/db/H2DatabaseTest.java b/test/net/sf/briar/db/H2DatabaseTest.java
index 406d49c9918e1af28ad53dbedf82aae2012005ef..98132c330fea13712f36ae66b4d4830b959af079 100644
--- a/test/net/sf/briar/db/H2DatabaseTest.java
+++ b/test/net/sf/briar/db/H2DatabaseTest.java
@@ -106,7 +106,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testPersistence() throws DbException {
+	public void testPersistence() throws Exception {
 		// Store some records
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
@@ -158,7 +158,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testContactIdsIncrease() throws DbException {
+	public void testContactIdsIncrease() throws Exception {
 		ContactId contactId1 = new ContactId(2);
 		ContactId contactId2 = new ContactId(3);
 		ContactId contactId3 = new ContactId(4);
@@ -188,7 +188,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testRatings() throws DbException {
+	public void testRatings() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -204,7 +204,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testUnsubscribingRemovesGroupMessage() throws DbException {
+	public void testUnsubscribingRemovesGroupMessage() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -222,7 +222,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testRemovingContactRemovesPrivateMessage() throws DbException {
+	public void testRemovingContactRemovesPrivateMessage() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -241,7 +241,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testSendablePrivateMessagesMustHaveStatusNew()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -280,7 +280,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testSendablePrivateMessagesMustFitCapacity()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -308,7 +308,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testSendableGroupMessagesMustHavePositiveSendability()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -346,7 +346,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testSendableGroupMessagesMustHaveStatusNew()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -388,7 +388,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testSendableGroupMessagesMustBeSubscribed() throws DbException {
+	public void testSendableGroupMessagesMustBeSubscribed() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -427,7 +427,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testSendableGroupMessagesMustBeNewerThanSubscriptions()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -462,7 +462,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testSendableGroupMessagesMustFitCapacity() throws DbException {
+	public void testSendableGroupMessagesMustFitCapacity() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -493,7 +493,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testSendableGroupMessagesMustBeVisible() throws DbException {
+	public void testSendableGroupMessagesMustBeVisible() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -525,7 +525,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testBatchesToAck() throws DbException {
+	public void testBatchesToAck() throws Exception {
 		BatchId batchId1 = new BatchId(TestUtils.getRandomId());
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
@@ -553,7 +553,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testDuplicateBatchesReceived() throws DbException {
+	public void testDuplicateBatchesReceived() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -579,7 +579,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testSameBatchCannotBeSentTwice() throws DbException {
+	public void testSameBatchCannotBeSentTwice() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -604,7 +604,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testSameBatchCanBeSentToDifferentContacts() throws DbException {
+	public void testSameBatchCanBeSentToDifferentContacts() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -627,7 +627,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testRemoveAckedBatch() throws DbException {
+	public void testRemoveAckedBatch() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -666,7 +666,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testRemoveLostBatch() throws DbException {
+	public void testRemoveLostBatch() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -707,7 +707,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testRetransmission() throws DbException {
+	public void testRetransmission() throws Exception {
 		BatchId[] ids = new BatchId[Database.RETRANSMIT_THRESHOLD + 5];
 		for(int i = 0; i < ids.length; i++) {
 			ids[i] = new BatchId(TestUtils.getRandomId());
@@ -749,7 +749,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testNoRetransmission() throws DbException {
+	public void testNoRetransmission() throws Exception {
 		BatchId[] ids = new BatchId[Database.RETRANSMIT_THRESHOLD * 2];
 		for(int i = 0; i < ids.length; i++) {
 			ids[i] = new BatchId(TestUtils.getRandomId());
@@ -782,7 +782,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testGetMessagesByAuthor() throws DbException {
+	public void testGetMessagesByAuthor() throws Exception {
 		AuthorId authorId1 = new AuthorId(TestUtils.getRandomId());
 		MessageId messageId1 = new MessageId(TestUtils.getRandomId());
 		Message message1 = new TestMessage(messageId1, null, groupId, authorId1,
@@ -811,7 +811,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testGetNumberOfSendableChildren() throws DbException {
+	public void testGetNumberOfSendableChildren() throws Exception {
 		MessageId childId1 = new MessageId(TestUtils.getRandomId());
 		MessageId childId2 = new MessageId(TestUtils.getRandomId());
 		MessageId childId3 = new MessageId(TestUtils.getRandomId());
@@ -852,7 +852,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testGetOldMessages() throws DbException {
+	public void testGetOldMessages() throws Exception {
 		MessageId messageId1 = new MessageId(TestUtils.getRandomId());
 		Message message1 = new TestMessage(messageId1, null, groupId, authorId,
 				timestamp + 1000, raw);
@@ -909,7 +909,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testCloseWaitsForCommit() throws DbException {
+	public void testCloseWaitsForCommit() throws Exception {
 		final AtomicBoolean transactionFinished = new AtomicBoolean(false);
 		final AtomicBoolean closed = new AtomicBoolean(false);
 		final AtomicBoolean error = new AtomicBoolean(false);
@@ -924,7 +924,7 @@ public class H2DatabaseTest extends TestCase {
 					db.close();
 					closed.set(true);
 					if(!transactionFinished.get()) error.set(true);
-				} catch(DbException e) {
+				} catch(Exception e) {
 					error.set(true);
 				}
 			}
@@ -947,7 +947,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testCloseWaitsForAbort() throws DbException {
+	public void testCloseWaitsForAbort() throws Exception {
 		final AtomicBoolean transactionFinished = new AtomicBoolean(false);
 		final AtomicBoolean closed = new AtomicBoolean(false);
 		final AtomicBoolean error = new AtomicBoolean(false);
@@ -962,7 +962,7 @@ public class H2DatabaseTest extends TestCase {
 					db.close();
 					closed.set(true);
 					if(!transactionFinished.get()) error.set(true);
-				} catch(DbException e) {
+				} catch(Exception e) {
 					error.set(true);
 				}
 			}
@@ -985,7 +985,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testUpdateTransportProperties() throws DbException {
+	public void testUpdateTransportProperties() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1027,7 +1027,7 @@ public class H2DatabaseTest extends TestCase {
 
 
 	@Test
-	public void testUpdateTransportConfig() throws DbException {
+	public void testUpdateTransportConfig() throws Exception {
 		Map<String, String> config = Collections.singletonMap("bar", "baz");
 		Map<String, String> config1 = Collections.singletonMap("baz", "bam");
 		Database<Connection> db = open(false);
@@ -1052,7 +1052,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testTransportsNotUpdatedIfTimestampIsOld() throws DbException {
+	public void testTransportsNotUpdatedIfTimestampIsOld() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1085,7 +1085,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testUpdateSubscriptions() throws DbException {
+	public void testUpdateSubscriptions() throws Exception {
 		GroupId groupId1 = new GroupId(TestUtils.getRandomId());
 		Group group1 = groupFactory.createGroup(groupId1, "Another group name",
 				null);
@@ -1112,7 +1112,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testSubscriptionsNotUpdatedIfTimestampIsOld()
-	throws DbException {
+	throws Exception {
 		GroupId groupId1 = new GroupId(TestUtils.getRandomId());
 		Group group1 = groupFactory.createGroup(groupId1, "Another group name",
 				null);
@@ -1141,7 +1141,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testGetMessageIfSendableReturnsNullIfNotInDatabase()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1159,7 +1159,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testGetMessageIfSendableReturnsNullIfSeen()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1182,7 +1182,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testGetMessageIfSendableReturnsNullIfNotSendable()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1204,7 +1204,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testGetMessageIfSendableReturnsNullIfOld() throws DbException {
+	public void testGetMessageIfSendableReturnsNullIfOld() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1229,7 +1229,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testGetMessageIfSendableReturnsMessage() throws DbException {
+	public void testGetMessageIfSendableReturnsMessage() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1254,7 +1254,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testSetStatusSeenIfVisibleRequiresMessageInDatabase()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1273,7 +1273,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testSetStatusSeenIfVisibleRequiresLocalSubscription()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1290,7 +1290,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testSetStatusSeenIfVisibleRequiresContactSubscription()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1309,7 +1309,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testSetStatusSeenIfVisibleRequiresVisibility()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1329,7 +1329,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testSetStatusSeenIfVisibleReturnsTrueIfAlreadySeen()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1351,7 +1351,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testSetStatusSeenIfVisibleReturnsTrueIfNew()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1372,7 +1372,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testVisibility() throws DbException {
+	public void testVisibility() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1395,7 +1395,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testGettingUnknownConnectionWindowReturnsDefault()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1414,7 +1414,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testConnectionWindow() throws DbException {
+	public void testConnectionWindow() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1442,7 +1442,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testGetGroupMessageParentWithNoParent() throws DbException {
+	public void testGetGroupMessageParentWithNoParent() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1462,7 +1462,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testGetGroupMessageParentWithAbsentParent() throws DbException {
+	public void testGetGroupMessageParentWithAbsentParent() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1485,7 +1485,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testGetGroupMessageParentWithParentInAnotherGroup()
-	throws DbException {
+	throws Exception {
 		GroupId groupId1 = new GroupId(TestUtils.getRandomId());
 		Group group1 = groupFactory.createGroup(groupId1, "Group name", null);
 		Database<Connection> db = open(false);
@@ -1514,7 +1514,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testGetGroupMessageParentWithPrivateParent()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1538,7 +1538,7 @@ public class H2DatabaseTest extends TestCase {
 
 	@Test
 	public void testGetGroupMessageParentWithParentInSameGroup()
-	throws DbException {
+	throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -1563,7 +1563,7 @@ public class H2DatabaseTest extends TestCase {
 	}
 
 	@Test
-	public void testExceptionHandling() throws DbException {
+	public void testExceptionHandling() throws Exception {
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 		try {
@@ -1578,7 +1578,7 @@ public class H2DatabaseTest extends TestCase {
 		db.close();
 	}
 
-	private Database<Connection> open(boolean resume) throws DbException {
+	private Database<Connection> open(boolean resume) throws Exception {
 		Database<Connection> db = new H2Database(testDir, password, MAX_SIZE,
 				connectionWindowFactory, groupFactory);
 		db.open(resume);
diff --git a/util/net/sf/briar/util/FileUtils.java b/util/net/sf/briar/util/FileUtils.java
index 360791e93420417387e7afec881c97aeddf462fe..b6310379addc43c0ad1ddd5f739875cb64e09a7f 100644
--- a/util/net/sf/briar/util/FileUtils.java
+++ b/util/net/sf/briar/util/FileUtils.java
@@ -75,11 +75,17 @@ public class FileUtils {
 		}
 	}
 
-	public static void delete(File f) {
-		if(f.isDirectory()) for(File child : f.listFiles()) delete(child);
+	public static void delete(File f) throws IOException {
+		if(f.isDirectory() && !isSymlink(f)) {
+			for(File child : f.listFiles()) delete(child);
+		}
 		f.delete();
 	}
 
+	private static boolean isSymlink(File f) throws IOException {
+		return org.apache.commons.io.FileUtils.isSymlink(f);
+	}
+
 	public interface Callback {
 
 		void processingFile(File f);