diff --git a/components/net/sf/briar/plugins/file/FilePlugin.java b/components/net/sf/briar/plugins/file/FilePlugin.java
index 185d3be5166db11d6f6dc68cb637d614c378300e..93c745fb008cc5f2ca302bdb25781b65a29d8cdf 100644
--- a/components/net/sf/briar/plugins/file/FilePlugin.java
+++ b/components/net/sf/briar/plugins/file/FilePlugin.java
@@ -91,7 +91,6 @@ abstract class FilePlugin implements BatchTransportPlugin {
 			OutputStream out = new FileOutputStream(f);
 			return new FileTransportWriter(f, out, capacity, this);
 		} catch(IOException e) {
-			e.printStackTrace();
 			f.delete();
 			return null;
 		}
diff --git a/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java b/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java
index 2a890d5b8c2567065ad6a4792cf06a84e2a1afbe..758c3e9e8e79561b092fae857a8819dd386b0cf5 100644
--- a/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java
+++ b/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java
@@ -4,14 +4,24 @@ import java.io.File;
 import java.io.IOException;
 import java.util.List;
 
+import net.sf.briar.api.TransportId;
+
 class RemovableDrivePlugin extends FilePlugin {
 
+	public static final int TRANSPORT_ID = 0;
+
+	private static final TransportId id = new TransportId(TRANSPORT_ID);
+
 	private final RemovableDriveFinder finder;
 
 	RemovableDrivePlugin(RemovableDriveFinder finder) {
 		this.finder = finder;
 	}
 
+	public TransportId getId() {
+		return id;
+	}
+
 	@Override
 	protected File chooseOutputDirectory() {
 		try {
@@ -19,7 +29,7 @@ class RemovableDrivePlugin extends FilePlugin {
 			if(drives.isEmpty()) return null;
 			String[] paths = new String[drives.size()];
 			for(int i = 0; i < paths.length; i++) {
-				paths[i] = drives.get(i).getAbsolutePath();
+				paths[i] = drives.get(i).getPath();
 			}
 			int i = callback.showChoice("REMOVABLE_DRIVE_CHOOSE_DRIVE", paths);
 			if(i == -1) return null;
diff --git a/components/net/sf/briar/plugins/file/UnixRemovableDriveFinder.java b/components/net/sf/briar/plugins/file/UnixRemovableDriveFinder.java
index 17a551bf7b614059b087efff30e659b2dd1b3380..0b5cac4014703548aa8030e5a6dd0ac458f9e94a 100644
--- a/components/net/sf/briar/plugins/file/UnixRemovableDriveFinder.java
+++ b/components/net/sf/briar/plugins/file/UnixRemovableDriveFinder.java
@@ -9,9 +9,7 @@ import java.util.Scanner;
 abstract class UnixRemovableDriveFinder implements RemovableDriveFinder {
 
 	protected abstract String getMountCommand();
-
 	protected abstract String parseMountPoint(String line);
-
 	protected abstract boolean isRemovableDriveMountPoint(String path);
 
 	public List<File> findRemovableDrives() throws IOException {
diff --git a/test/build.xml b/test/build.xml
index 7238b1a32c4eedb983e76e5840381062d9840068..73ecb1176dc5ac5bf5ae1dec4b6c12f47aa7013d 100644
--- a/test/build.xml
+++ b/test/build.xml
@@ -25,6 +25,7 @@
 			<test name='net.sf.briar.i18n.FontManagerTest'/>
 			<test name='net.sf.briar.i18n.I18nTest'/>
 			<test name='net.sf.briar.invitation.InvitationWorkerTest'/>
+			<test name='net.sf.briar.plugins.file.RemovableDrivePluginTest'/>
 			<test name='net.sf.briar.protocol.AckReaderTest'/>
 			<test name='net.sf.briar.protocol.BatchReaderTest'/>
 			<test name='net.sf.briar.protocol.ConsumersTest'/>
diff --git a/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java b/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf1a00077e283583c1f7fc4bd54f68336bdef9af
--- /dev/null
+++ b/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java
@@ -0,0 +1,244 @@
+package net.sf.briar.plugins.file;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.TestCase;
+import net.sf.briar.TestUtils;
+import net.sf.briar.api.ContactId;
+import net.sf.briar.api.transport.batch.BatchTransportCallback;
+import net.sf.briar.api.transport.batch.BatchTransportWriter;
+
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RemovableDrivePluginTest extends TestCase {
+
+	private final File testDir = TestUtils.getTestDirectory();
+	private final ContactId contactId = new ContactId(0);
+
+	@Before
+	public void setUp() {
+		testDir.mkdirs();
+	}
+
+	@Test
+	public void testGetId() {
+		Mockery context = new Mockery();
+		final RemovableDriveFinder finder =
+			context.mock(RemovableDriveFinder.class);
+		RemovableDrivePlugin plugin = new RemovableDrivePlugin(finder);
+
+		assertEquals(RemovableDrivePlugin.TRANSPORT_ID,
+				plugin.getId().getInt());
+
+		context.assertIsSatisfied();
+	}
+
+	@Test
+	public void testWriterIsNullIfNoDrivesAreFound() throws Exception {
+		final List<File> drives = Collections.emptyList();
+
+		Mockery context = new Mockery();
+		final RemovableDriveFinder finder =
+			context.mock(RemovableDriveFinder.class);
+		final BatchTransportCallback callback =
+			context.mock(BatchTransportCallback.class);
+		context.checking(new Expectations() {{
+			oneOf(finder).findRemovableDrives();
+			will(returnValue(drives));
+		}});
+		RemovableDrivePlugin plugin = new RemovableDrivePlugin(finder);
+		plugin.start(null, null, null, callback);
+
+		assertNull(plugin.createWriter(contactId));
+
+		context.assertIsSatisfied();
+	}
+
+	@Test
+	public void testWriterIsNullIfNoDriveIsChosen() throws Exception {
+		final File drive1 = new File(testDir, "1");
+		final File drive2 = new File(testDir, "2");
+		final List<File> drives = new ArrayList<File>();
+		drives.add(drive1);
+		drives.add(drive2);
+
+		Mockery context = new Mockery();
+		final RemovableDriveFinder finder =
+			context.mock(RemovableDriveFinder.class);
+		final BatchTransportCallback callback =
+			context.mock(BatchTransportCallback.class);
+		context.checking(new Expectations() {{
+			oneOf(finder).findRemovableDrives();
+			will(returnValue(drives));
+			oneOf(callback).showChoice(with(any(String.class)),
+					with(any(String[].class)));
+			will(returnValue(-1)); // The user cancelled the choice
+		}});
+		RemovableDrivePlugin plugin = new RemovableDrivePlugin(finder);
+		plugin.start(null, null, null, callback);
+
+		assertNull(plugin.createWriter(contactId));
+		File[] files = drive1.listFiles();
+		assertTrue(files == null || files.length == 0);
+
+		context.assertIsSatisfied();
+	}
+
+	@Test
+	public void testWriterIsNullIfOutputDirDoesNotExist() throws Exception {
+		final File drive1 = new File(testDir, "1");
+		final File drive2 = new File(testDir, "2");
+		final List<File> drives = new ArrayList<File>();
+		drives.add(drive1);
+		drives.add(drive2);
+
+		Mockery context = new Mockery();
+		final RemovableDriveFinder finder =
+			context.mock(RemovableDriveFinder.class);
+		final BatchTransportCallback callback =
+			context.mock(BatchTransportCallback.class);
+		context.checking(new Expectations() {{
+			oneOf(finder).findRemovableDrives();
+			will(returnValue(drives));
+			oneOf(callback).showChoice(with(any(String.class)),
+					with(any(String[].class)));
+			will(returnValue(0)); // The user chose drive1 but it doesn't exist
+		}});
+		RemovableDrivePlugin plugin = new RemovableDrivePlugin(finder);
+		plugin.start(null, null, null, callback);
+
+		assertNull(plugin.createWriter(contactId));
+		File[] files = drive1.listFiles();
+		assertTrue(files == null || files.length == 0);
+
+		context.assertIsSatisfied();
+	}
+
+	@Test
+	public void testWriterIsNullIfOutputDirIsAFile() throws Exception {
+		final File drive1 = new File(testDir, "1");
+		final File drive2 = new File(testDir, "2");
+		final List<File> drives = new ArrayList<File>();
+		drives.add(drive1);
+		drives.add(drive2);
+		// Create drive1 as a file rather than a directory
+		assertTrue(drive1.createNewFile());
+
+		Mockery context = new Mockery();
+		final RemovableDriveFinder finder =
+			context.mock(RemovableDriveFinder.class);
+		final BatchTransportCallback callback =
+			context.mock(BatchTransportCallback.class);
+		context.checking(new Expectations() {{
+			oneOf(finder).findRemovableDrives();
+			will(returnValue(drives));
+			oneOf(callback).showChoice(with(any(String.class)),
+					with(any(String[].class)));
+			will(returnValue(0)); // The user chose drive1 but it's not a dir
+		}});
+		RemovableDrivePlugin plugin = new RemovableDrivePlugin(finder);
+		plugin.start(null, null, null, callback);
+
+		assertNull(plugin.createWriter(contactId));
+		File[] files = drive1.listFiles();
+		assertTrue(files == null || files.length == 0);
+
+		context.assertIsSatisfied();
+	}
+
+	@Test
+	public void testWriterIsNotNullIfOutputDirIsADir() throws Exception {
+		final File drive1 = new File(testDir, "1");
+		final File drive2 = new File(testDir, "2");
+		final List<File> drives = new ArrayList<File>();
+		drives.add(drive1);
+		drives.add(drive2);
+		// Create drive1 as a directory
+		assertTrue(drive1.mkdir());
+
+		Mockery context = new Mockery();
+		final RemovableDriveFinder finder =
+			context.mock(RemovableDriveFinder.class);
+		final BatchTransportCallback callback =
+			context.mock(BatchTransportCallback.class);
+		context.checking(new Expectations() {{
+			oneOf(finder).findRemovableDrives();
+			will(returnValue(drives));
+			oneOf(callback).showChoice(with(any(String.class)),
+					with(any(String[].class)));
+			will(returnValue(0)); // The user chose drive1
+		}});
+		RemovableDrivePlugin plugin = new RemovableDrivePlugin(finder);
+		plugin.start(null, null, null, callback);
+
+		assertNotNull(plugin.createWriter(contactId));
+		// The output file should exist and should be empty
+		File[] files = drive1.listFiles();
+		assertNotNull(files);
+		assertEquals(1, files.length);
+		assertEquals(0L, files[0].length());
+
+		context.assertIsSatisfied();
+	}
+
+	@Test
+	public void testWritingToWriter() throws Exception {
+		final File drive1 = new File(testDir, "1");
+		final File drive2 = new File(testDir, "2");
+		final List<File> drives = new ArrayList<File>();
+		drives.add(drive1);
+		drives.add(drive2);
+		// Create drive1 as a directory
+		assertTrue(drive1.mkdir());
+
+		Mockery context = new Mockery();
+		final RemovableDriveFinder finder =
+			context.mock(RemovableDriveFinder.class);
+		final BatchTransportCallback callback =
+			context.mock(BatchTransportCallback.class);
+		context.checking(new Expectations() {{
+			oneOf(finder).findRemovableDrives();
+			will(returnValue(drives));
+			oneOf(callback).showChoice(with(any(String.class)),
+					with(any(String[].class)));
+			will(returnValue(0)); // The user chose drive1
+			oneOf(callback).showMessage(with(any(String.class)));
+		}});
+		RemovableDrivePlugin plugin = new RemovableDrivePlugin(finder);
+		plugin.start(null, null, null, callback);
+
+		BatchTransportWriter writer = plugin.createWriter(contactId);
+		assertNotNull(writer);
+		// The output file should exist and should be empty
+		File[] files = drive1.listFiles();
+		assertNotNull(files);
+		assertEquals(1, files.length);
+		assertEquals(0L, files[0].length());
+		// Writing to the output stream should increase the size of the file
+		OutputStream out = writer.getOutputStream();
+		out.write(new byte[123]);
+		out.flush();
+		out.close();
+		writer.finish();
+		assertEquals(123L, files[0].length());
+		// Disposing of the writer should delete the file
+		writer.dispose();
+		files = drive1.listFiles();
+		assertTrue(files == null || files.length == 0);
+
+		context.assertIsSatisfied();
+	}
+
+	@After
+	public void tearDown() {
+		TestUtils.deleteTestDirectory(testDir);
+	}
+}
diff --git a/test/net/sf/briar/plugins/file/TestFilePlugin.java b/test/net/sf/briar/plugins/file/TestFilePlugin.java
deleted file mode 100644
index b3a065a6cbbd30b9d0742512836c657fa630c756..0000000000000000000000000000000000000000
--- a/test/net/sf/briar/plugins/file/TestFilePlugin.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package net.sf.briar.plugins.file;
-
-import java.io.File;
-
-public class TestFilePlugin extends FilePlugin {
-
-	private final File outputDir;
-	private final long capacity;
-
-	public TestFilePlugin(File outputDir, long capacity) {
-		this.outputDir = outputDir;
-		this.capacity = capacity;
-	}
-
-	@Override
-	protected File chooseOutputDirectory() {
-		return outputDir;
-	}
-
-	@Override
-	protected void writerFinished(File f) {
-		// Nothing to do
-	}
-
-	@Override
-	protected long getCapacity(String path) {
-		return capacity;
-	}
-}