diff --git a/briar-android/src/net/sf/briar/android/AndroidFileUtils.java b/briar-android/src/net/sf/briar/android/AndroidFileUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..f7884c5b5efc1c23248dca6ec24c116f142c5973
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/AndroidFileUtils.java
@@ -0,0 +1,15 @@
+package net.sf.briar.android;
+
+import java.io.File;
+import java.io.IOException;
+
+import net.sf.briar.api.os.FileUtils;
+import android.os.StatFs;
+
+class AndroidFileUtils implements FileUtils {
+
+	public long getFreeSpace(File f) throws IOException {
+		StatFs s = new StatFs(f.getAbsolutePath());
+		return (long) s.getAvailableBlocks() * s.getBlockSize();
+	}
+}
diff --git a/briar-android/src/net/sf/briar/android/AndroidModule.java b/briar-android/src/net/sf/briar/android/AndroidModule.java
index d9b0907af3eb2f11c368fc9543c96f46c83613a8..817ca22b894687af1a35b05795918435bc9bf726 100644
--- a/briar-android/src/net/sf/briar/android/AndroidModule.java
+++ b/briar-android/src/net/sf/briar/android/AndroidModule.java
@@ -18,6 +18,7 @@ import net.sf.briar.api.android.ReferenceManager;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.lifecycle.LifecycleManager;
 import net.sf.briar.api.lifecycle.ShutdownManager;
+import net.sf.briar.api.os.FileUtils;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.plugins.duplex.DuplexPluginConfig;
 import net.sf.briar.api.plugins.duplex.DuplexPluginFactory;
@@ -52,6 +53,7 @@ public class AndroidModule extends AbstractModule {
 		bind(AndroidExecutor.class).to(AndroidExecutorImpl.class);
 		bind(ReferenceManager.class).to(
 				ReferenceManagerImpl.class).in(Singleton.class);
+		bind(FileUtils.class).to(AndroidFileUtils.class);
 	}
 
 	@Provides @Singleton @DatabaseUiExecutor
diff --git a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
index 52ab1f12b940efadaa18b6d69b8bed01aa84a133..4f7303ec640eeb97069eb3b8f6d31a588490bca6 100644
--- a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
+++ b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
@@ -62,8 +62,8 @@ import com.google.inject.Inject;
 
 public class HomeScreenActivity extends RoboActivity {
 
-	// This build expires on 31 July 2013
-	private static final long EXPIRY_DATE = 1375228800 * 1000L;
+	// This build expires on 15 August 2013
+	private static final long EXPIRY_DATE = 1376524800 * 1000L;
 
 	private static final Logger LOG =
 			Logger.getLogger(HomeScreenActivity.class.getName());
diff --git a/briar-api/src/net/sf/briar/api/os/FileUtils.java b/briar-api/src/net/sf/briar/api/os/FileUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..d52d4ca6eb4813986da551a3c8949e04a11e22f1
--- /dev/null
+++ b/briar-api/src/net/sf/briar/api/os/FileUtils.java
@@ -0,0 +1,9 @@
+package net.sf.briar.api.os;
+
+import java.io.File;
+import java.io.IOException;
+
+public interface FileUtils {
+
+	long getFreeSpace(File f) throws IOException;
+}
diff --git a/briar-core/.classpath b/briar-core/.classpath
index 7efe06ab282cc632f536f4085b5721e6f825c5dc..78401b100347dcbaf1535c87602856ca61036e62 100644
--- a/briar-core/.classpath
+++ b/briar-core/.classpath
@@ -4,7 +4,6 @@
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
 	<classpathentry combineaccessrules="false" kind="src" path="/briar-api"/>
 	<classpathentry kind="lib" path="/briar-api/libs/guice-3.0-no_aop.jar"/>
-	<classpathentry kind="lib" path="libs/commons-io-2.0.1.jar"/>
 	<classpathentry kind="lib" path="libs/h2small-1.3.170.jar"/>
 	<classpathentry kind="lib" path="libs/javax.inject.jar"/>
 	<classpathentry kind="lib" path="libs/sc-light-jdk15on-1.47.0.3-SNAPSHOT.jar" sourcepath="libs/source/sc-light-jdk15on-1.47.0.3-SNAPSHOT-source.jar"/>
diff --git a/briar-core/src/net/sf/briar/db/DatabaseModule.java b/briar-core/src/net/sf/briar/db/DatabaseModule.java
index eb625c951674d1aa79af63f16b4c9d8d8f471f80..87f629c810d4566acdaf78bcfeb24e503ae737b9 100644
--- a/briar-core/src/net/sf/briar/db/DatabaseModule.java
+++ b/briar-core/src/net/sf/briar/db/DatabaseModule.java
@@ -17,6 +17,7 @@ import net.sf.briar.api.db.DatabaseConfig;
 import net.sf.briar.api.db.DatabaseExecutor;
 import net.sf.briar.api.lifecycle.LifecycleManager;
 import net.sf.briar.api.lifecycle.ShutdownManager;
+import net.sf.briar.api.os.FileUtils;
 
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
@@ -45,8 +46,9 @@ public class DatabaseModule extends AbstractModule {
 	}
 
 	@Provides
-	Database<Connection> getDatabase(DatabaseConfig config) {
-		return new H2Database(config, new SystemClock());
+	Database<Connection> getDatabase(DatabaseConfig config,
+			FileUtils fileUtils) {
+		return new H2Database(config, fileUtils, new SystemClock());
 	}
 
 	@Provides @Singleton
diff --git a/briar-core/src/net/sf/briar/db/H2Database.java b/briar-core/src/net/sf/briar/db/H2Database.java
index 4455ee89c7f8ae418f0079cbb051ff90ec07767b..a21aba6d057cc2566cfff0513fe5e9cb80546076 100644
--- a/briar-core/src/net/sf/briar/db/H2Database.java
+++ b/briar-core/src/net/sf/briar/db/H2Database.java
@@ -11,7 +11,7 @@ import java.util.Properties;
 import net.sf.briar.api.clock.Clock;
 import net.sf.briar.api.db.DatabaseConfig;
 import net.sf.briar.api.db.DbException;
-import net.sf.briar.util.FileUtils;
+import net.sf.briar.api.os.FileUtils;
 import net.sf.briar.util.StringUtils;
 
 import com.google.inject.Inject;
@@ -25,12 +25,14 @@ class H2Database extends JdbcDatabase {
 	private static final String SECRET_TYPE = "BINARY(32)";
 
 	private final DatabaseConfig config;
+	private final FileUtils fileUtils;
 	private final String url;
 
 	@Inject
-	H2Database(DatabaseConfig config, Clock clock) {
+	H2Database(DatabaseConfig config, FileUtils fileUtils, Clock clock) {
 		super(HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE, clock);
 		this.config = config;
+		this.fileUtils = fileUtils;
 		String path = new File(config.getDatabaseDirectory(), "db").getPath();
 		url = "jdbc:h2:split:" + path + ";CIPHER=AES;MULTI_THREADED=1"
 				+ ";WRITE_DELAY=0;DB_CLOSE_ON_EXIT=false";
@@ -56,7 +58,7 @@ class H2Database extends JdbcDatabase {
 		File dir = config.getDatabaseDirectory();
 		long maxSize = config.getMaxSize();
 		try {
-			long free = FileUtils.getFreeSpace(dir);
+			long free = fileUtils.getFreeSpace(dir);
 			long used = getDiskSpace(dir);
 			long quota = maxSize - used;
 			long min =  Math.min(free, quota);
diff --git a/briar-core/src/net/sf/briar/plugins/file/FilePlugin.java b/briar-core/src/net/sf/briar/plugins/file/FilePlugin.java
index 2064c377b399f2c41517d6288c2772111ca94ae4..e2c7af542020c78329cc8bc50af4a4887ca95ce7 100644
--- a/briar-core/src/net/sf/briar/plugins/file/FilePlugin.java
+++ b/briar-core/src/net/sf/briar/plugins/file/FilePlugin.java
@@ -13,19 +13,19 @@ import java.util.concurrent.Executor;
 import java.util.logging.Logger;
 
 import net.sf.briar.api.ContactId;
+import net.sf.briar.api.os.FileUtils;
 import net.sf.briar.api.plugins.simplex.SimplexPlugin;
 import net.sf.briar.api.plugins.simplex.SimplexPluginCallback;
 import net.sf.briar.api.plugins.simplex.SimplexTransportReader;
 import net.sf.briar.api.plugins.simplex.SimplexTransportWriter;
 
-import org.apache.commons.io.FileSystemUtils;
-
 public abstract class FilePlugin implements SimplexPlugin {
 
 	private static final Logger LOG =
 			Logger.getLogger(FilePlugin.class.getName());
 
 	protected final Executor pluginExecutor;
+	protected final FileUtils fileUtils;
 	protected final SimplexPluginCallback callback;
 	protected final int maxFrameLength;
 	protected final long maxLatency;
@@ -37,10 +37,11 @@ public abstract class FilePlugin implements SimplexPlugin {
 	protected abstract void writerFinished(File f);
 	protected abstract void readerFinished(File f);
 
-	protected FilePlugin(Executor pluginExecutor,
+	protected FilePlugin(Executor pluginExecutor, FileUtils fileUtils,
 			SimplexPluginCallback callback, int maxFrameLength,
 			long maxLatency) {
 		this.pluginExecutor = pluginExecutor;
+		this.fileUtils = fileUtils;
 		this.callback = callback;
 		this.maxFrameLength = maxFrameLength;
 		this.maxLatency = maxLatency;
@@ -81,7 +82,7 @@ public abstract class FilePlugin implements SimplexPlugin {
 		if(dir == null || !dir.exists() || !dir.isDirectory()) return null;
 		File f = new File(dir, filename);
 		try {
-			long capacity = getCapacity(dir.getPath());
+			long capacity = fileUtils.getFreeSpace(dir);
 			if(capacity < MIN_CONNECTION_LENGTH) return null;
 			OutputStream out = new FileOutputStream(f);
 			return new FileTransportWriter(f, out, capacity, this);
@@ -92,10 +93,6 @@ public abstract class FilePlugin implements SimplexPlugin {
 		}
 	}
 
-	private long getCapacity(String path) throws IOException {
-		return FileSystemUtils.freeSpaceKb(path) * 1024;
-	}
-
 	protected void createReaderFromFile(final File f) {
 		if(!running) return;
 		pluginExecutor.execute(new ReaderCreator(f));
diff --git a/briar-core/src/net/sf/briar/util/FileUtils.java b/briar-core/src/net/sf/briar/util/FileUtils.java
deleted file mode 100644
index 3a940bb738f2f6dac893b6a0d1ad2b3535a5c766..0000000000000000000000000000000000000000
--- a/briar-core/src/net/sf/briar/util/FileUtils.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package net.sf.briar.util;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.CodeSource;
-
-import org.apache.commons.io.FileSystemUtils;
-
-public class FileUtils {
-
-	/**
-	 * Returns the directory where Briar is installed.
-	 */
-	public static File getBriarDirectory() {
-		CodeSource c = FileUtils.class.getProtectionDomain().getCodeSource();
-		File f = new File(c.getLocation().getPath());
-		assert f.exists();
-		if(f.isFile()) {
-			// Running from a jar - return the jar's grandparent
-			f = f.getParentFile().getParentFile();
-		} else {
-			// Running from Eclipse
-			f = new File(f.getParentFile(), "Briar");
-		}
-		assert f.exists();
-		assert f.isDirectory();
-		return f;
-	}
-
-	/**
-	 * Creates and returns a temporary file.
-	 */
-	public static File createTempFile() throws IOException {
-		String rand = String.valueOf(1000 + (int) (Math.random() * 9000));
-		return File.createTempFile(rand, null);
-	}
-
-	/**
-	 * Copies the contents of the source file to the destination file.
-	 */
-	public static void copy(File src, File dest) throws IOException {
-		FileInputStream in = new FileInputStream(src);
-		copy(in, dest);
-	}
-
-	/**
-	 * Copies the contents of the input stream to the destination file.
-	 */
-	public static void copy(InputStream in, File dest) throws IOException {
-		FileOutputStream out = new FileOutputStream(dest);
-		byte[] buf = new byte[1024];
-		int i;
-		while((i = in.read(buf, 0, buf.length)) != -1) out.write(buf, 0, i);
-		in.close();
-		out.flush();
-		out.close();
-	}
-
-	/**
-	 * Copies the source file or directory to the destination directory. If the
-	 * callback is not null it's called once for each file created.
-	 */
-	public static void copyRecursively(File src, File dest, Callback callback)
-			throws IOException {
-		assert dest.exists();
-		assert dest.isDirectory();
-		dest = new File(dest, src.getName());
-		if(src.isDirectory()) {
-			dest.mkdir();
-			for(File f : src.listFiles()) copyRecursively(f, dest, callback);
-		} else {
-			if(callback != null) callback.processingFile(dest);
-			copy(src, dest);
-		}
-	}
-
-	public static void delete(File f) throws IOException {
-		if(f.isDirectory() && !org.apache.commons.io.FileUtils.isSymlink(f)) {
-			for(File child : f.listFiles()) delete(child);
-		}
-		f.delete();
-	}
-
-	public static long getFreeSpace(File f) throws IOException {
-		return FileSystemUtils.freeSpaceKb(f.getAbsolutePath()) * 1024;
-	}
-
-	public interface Callback {
-
-		void processingFile(File f);
-	}
-}
diff --git a/briar-desktop/.classpath b/briar-desktop/.classpath
index 5daeb37d40ebfd5b8b9d833bd47a6355724bf123..93f439757ceb421d52f288555e140751c0527114 100644
--- a/briar-desktop/.classpath
+++ b/briar-desktop/.classpath
@@ -7,6 +7,7 @@
 	<classpathentry kind="lib" path="/briar-api/libs/guice-3.0-no_aop.jar"/>
 	<classpathentry kind="lib" path="libs/bluecove-2.1.1-SNAPSHOT-briar.jar"/>
 	<classpathentry kind="lib" path="libs/bluecove-gpl-2.1.1-SNAPSHOT.jar"/>
+	<classpathentry kind="lib" path="libs/commons-io-2.0.1.jar"/>
 	<classpathentry kind="lib" path="libs/jna-3.5.2-SNAPSHOT.jar"/>
 	<classpathentry kind="lib" path="libs/jnotify-0.93.jar"/>
 	<classpathentry kind="lib" path="libs/jssc-0.9-briar.jar" sourcepath="libs/source/jssc-0.9-briar-source.jar"/>
diff --git a/briar-core/libs/commons-io-2.0.1.jar b/briar-desktop/libs/commons-io-2.0.1.jar
similarity index 100%
rename from briar-core/libs/commons-io-2.0.1.jar
rename to briar-desktop/libs/commons-io-2.0.1.jar
diff --git a/briar-desktop/src/net/sf/briar/os/DesktopOsModule.java b/briar-desktop/src/net/sf/briar/os/DesktopOsModule.java
new file mode 100644
index 0000000000000000000000000000000000000000..b0a8a087b436ecd7e6b83205bda6ee244d56716d
--- /dev/null
+++ b/briar-desktop/src/net/sf/briar/os/DesktopOsModule.java
@@ -0,0 +1,13 @@
+package net.sf.briar.os;
+
+import net.sf.briar.api.os.FileUtils;
+
+import com.google.inject.AbstractModule;
+
+public class DesktopOsModule extends AbstractModule {
+
+	@Override
+	protected void configure() {
+		bind(FileUtils.class).to(FileUtilsImpl.class);
+	}
+}
diff --git a/briar-desktop/src/net/sf/briar/os/FileUtilsImpl.java b/briar-desktop/src/net/sf/briar/os/FileUtilsImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..fc796dcf6480214cfa48a509e68ff6a0418d171c
--- /dev/null
+++ b/briar-desktop/src/net/sf/briar/os/FileUtilsImpl.java
@@ -0,0 +1,15 @@
+package net.sf.briar.os;
+
+import java.io.File;
+import java.io.IOException;
+
+import net.sf.briar.api.os.FileUtils;
+
+import org.apache.commons.io.FileSystemUtils;
+
+class FileUtilsImpl implements FileUtils {
+
+	public long getFreeSpace(File f) throws IOException {
+		return FileSystemUtils.freeSpaceKb(f.getAbsolutePath()) * 1024;
+	}
+}
diff --git a/briar-desktop/src/net/sf/briar/plugins/DesktopPluginsModule.java b/briar-desktop/src/net/sf/briar/plugins/DesktopPluginsModule.java
index cea66b635de9f8549a3e60e3313f305a8e1719e6..76ad61ea5961476976d378386fee8dfcff25349b 100644
--- a/briar-desktop/src/net/sf/briar/plugins/DesktopPluginsModule.java
+++ b/briar-desktop/src/net/sf/briar/plugins/DesktopPluginsModule.java
@@ -6,6 +6,7 @@ import java.util.concurrent.Executor;
 
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.lifecycle.ShutdownManager;
+import net.sf.briar.api.os.FileUtils;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.plugins.duplex.DuplexPluginConfig;
 import net.sf.briar.api.plugins.duplex.DuplexPluginFactory;
@@ -27,9 +28,9 @@ public class DesktopPluginsModule extends AbstractModule {
 
 	@Provides
 	SimplexPluginConfig getSimplexPluginConfig(
-			@PluginExecutor Executor pluginExecutor) {
+			@PluginExecutor Executor pluginExecutor, FileUtils fileUtils) {
 		SimplexPluginFactory removable =
-				new RemovableDrivePluginFactory(pluginExecutor);
+				new RemovableDrivePluginFactory(pluginExecutor, fileUtils);
 		final Collection<SimplexPluginFactory> factories =
 				Arrays.asList(removable);
 		return new SimplexPluginConfig() {
diff --git a/briar-desktop/src/net/sf/briar/plugins/file/RemovableDrivePlugin.java b/briar-desktop/src/net/sf/briar/plugins/file/RemovableDrivePlugin.java
index 1cc9936eeacba758eda307c35f06fb47beb4983e..05c981c6d8a3f02fb9f7a705159ad7161670fa91 100644
--- a/briar-desktop/src/net/sf/briar/plugins/file/RemovableDrivePlugin.java
+++ b/briar-desktop/src/net/sf/briar/plugins/file/RemovableDrivePlugin.java
@@ -13,6 +13,7 @@ import java.util.logging.Logger;
 
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportId;
+import net.sf.briar.api.os.FileUtils;
 import net.sf.briar.api.plugins.simplex.SimplexPluginCallback;
 import net.sf.briar.util.StringUtils;
 
@@ -31,11 +32,11 @@ implements RemovableDriveMonitor.Callback {
 	private final RemovableDriveFinder finder;
 	private final RemovableDriveMonitor monitor;
 
-	RemovableDrivePlugin(Executor pluginExecutor,
+	RemovableDrivePlugin(Executor pluginExecutor, FileUtils fileUtils,
 			SimplexPluginCallback callback, RemovableDriveFinder finder,
 			RemovableDriveMonitor monitor, int maxFrameLength,
 			long maxLatency) {
-		super(pluginExecutor, callback, maxFrameLength, maxLatency);
+		super(pluginExecutor, fileUtils, callback, maxFrameLength, maxLatency);
 		this.finder = finder;
 		this.monitor = monitor;
 	}
diff --git a/briar-desktop/src/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java b/briar-desktop/src/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java
index 1ed88d03b6b792750942f3cb8d78a2d289bff370..6af65eda85b9fc786259ce51c72ccab17180213b 100644
--- a/briar-desktop/src/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java
+++ b/briar-desktop/src/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java
@@ -5,6 +5,7 @@ import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 import java.util.concurrent.Executor;
 
 import net.sf.briar.api.TransportId;
+import net.sf.briar.api.os.FileUtils;
 import net.sf.briar.api.plugins.simplex.SimplexPlugin;
 import net.sf.briar.api.plugins.simplex.SimplexPluginCallback;
 import net.sf.briar.api.plugins.simplex.SimplexPluginFactory;
@@ -17,9 +18,12 @@ public class RemovableDrivePluginFactory implements SimplexPluginFactory {
 	private static final long POLLING_INTERVAL = 10 * 1000; // 10 seconds
 
 	private final Executor pluginExecutor;
+	private final FileUtils fileUtils;
 
-	public RemovableDrivePluginFactory(Executor pluginExecutor) {
+	public RemovableDrivePluginFactory(Executor pluginExecutor,
+			FileUtils fileUtils) {
 		this.pluginExecutor = pluginExecutor;
+		this.fileUtils = fileUtils;
 	}
 
 	public TransportId getId() {
@@ -47,7 +51,7 @@ public class RemovableDrivePluginFactory implements SimplexPluginFactory {
 		} else {
 			return null;
 		}
-		return new RemovableDrivePlugin(pluginExecutor, callback, finder,
-				monitor, MAX_FRAME_LENGTH, MAX_LATENCY);
+		return new RemovableDrivePlugin(pluginExecutor, fileUtils, callback,
+				finder, monitor, MAX_FRAME_LENGTH, MAX_LATENCY);
 	}
 }
diff --git a/briar-tests/.classpath b/briar-tests/.classpath
index af3f2eaf88f5b3daacddb471b18b60ec581fa7cc..548a670c9619e718f07de3175b5e5f49abc19da4 100644
--- a/briar-tests/.classpath
+++ b/briar-tests/.classpath
@@ -6,7 +6,7 @@
 	<classpathentry combineaccessrules="false" kind="src" path="/briar-core"/>
 	<classpathentry combineaccessrules="false" kind="src" path="/briar-desktop"/>
 	<classpathentry kind="lib" path="/briar-api/libs/guice-3.0-no_aop.jar"/>
-	<classpathentry kind="lib" path="/briar-core/libs/commons-io-2.0.1.jar"/>
+	<classpathentry kind="lib" path="/briar-desktop/libs/commons-io-2.0.1.jar"/>
 	<classpathentry kind="lib" path="/briar-desktop/libs/jnotify-0.93.jar"/>
 	<classpathentry kind="lib" path="/briar-desktop/libs/jssc-0.9-briar.jar" sourcepath="/briar-desktop/libs/source/jssc-0.9-briar-source.jar"/>
 	<classpathentry kind="lib" path="libs/hamcrest-core-1.1.jar"/>
diff --git a/briar-tests/build.xml b/briar-tests/build.xml
index c417febb4b09a8ae0281351f589175aadb0105d5..c316b4c8d0b07e75900ed7b1646f7969e0882e78 100644
--- a/briar-tests/build.xml
+++ b/briar-tests/build.xml
@@ -132,7 +132,6 @@
 			<test name='net.sf.briar.transport.TransportIntegrationTest'/>
 			<test name='net.sf.briar.transport.TransportConnectionRecogniserTest'/>
 			<test name='net.sf.briar.util.ByteUtilsTest'/>
-			<test name='net.sf.briar.util.FileUtilsTest'/>
 			<test name='net.sf.briar.util.StringUtilsTest'/>
 			<test name='net.sf.briar.util.ZipUtilsTest'/>
 		</junit>
diff --git a/briar-tests/src/net/sf/briar/TestDatabaseModule.java b/briar-tests/src/net/sf/briar/TestDatabaseModule.java
index 0082dbbe9d1b9dd182378f59c0dccf88d51ae558..8ea2390ce7cb8190afc9d0b7a3e695e8fcd326ff 100644
--- a/briar-tests/src/net/sf/briar/TestDatabaseModule.java
+++ b/briar-tests/src/net/sf/briar/TestDatabaseModule.java
@@ -3,6 +3,7 @@ package net.sf.briar;
 import java.io.File;
 
 import net.sf.briar.api.db.DatabaseConfig;
+import net.sf.briar.api.os.FileUtils;
 
 import com.google.inject.AbstractModule;
 
@@ -24,5 +25,6 @@ public class TestDatabaseModule extends AbstractModule {
 
 	protected void configure() {
 		bind(DatabaseConfig.class).toInstance(config);
+		bind(FileUtils.class).to(TestFileUtils.class);
 	}
 }
diff --git a/briar-tests/src/net/sf/briar/TestFileUtils.java b/briar-tests/src/net/sf/briar/TestFileUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e0d12f7696c8c99fa7ed454426e72bb25a29318
--- /dev/null
+++ b/briar-tests/src/net/sf/briar/TestFileUtils.java
@@ -0,0 +1,15 @@
+package net.sf.briar;
+
+import java.io.File;
+import java.io.IOException;
+
+import net.sf.briar.api.os.FileUtils;
+
+import org.apache.commons.io.FileSystemUtils;
+
+public class TestFileUtils implements FileUtils {
+
+	public long getFreeSpace(File f) throws IOException {
+		return FileSystemUtils.freeSpaceKb(f.getAbsolutePath()) * 1024;
+	}
+}
diff --git a/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java b/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java
index 0757dfa1034f918b9aef98511d86673978c35347..2922c1dc4101aee719c94d0cee9c474990a2a90f 100644
--- a/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java
+++ b/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java
@@ -21,6 +21,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestDatabaseConfig;
+import net.sf.briar.TestFileUtils;
 import net.sf.briar.TestMessage;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.Author;
@@ -1931,7 +1932,7 @@ public class H2DatabaseTest extends BriarTestCase {
 
 	private Database<Connection> open(boolean resume) throws Exception {
 		Database<Connection> db = new H2Database(new TestDatabaseConfig(testDir,
-				MAX_SIZE), new SystemClock());
+				MAX_SIZE), new TestFileUtils(), new SystemClock());
 		if(!resume) TestUtils.deleteTestDirectory(testDir);
 		db.open();
 		return db;
diff --git a/briar-tests/src/net/sf/briar/plugins/file/RemovableDrivePluginTest.java b/briar-tests/src/net/sf/briar/plugins/file/RemovableDrivePluginTest.java
index 6a83e1dae11f9c1568961e48c7d60de2abd088ac..ba96c4be30ebc55ffa282caf6fe225d83b114e3c 100644
--- a/briar-tests/src/net/sf/briar/plugins/file/RemovableDrivePluginTest.java
+++ b/briar-tests/src/net/sf/briar/plugins/file/RemovableDrivePluginTest.java
@@ -12,8 +12,10 @@ import java.util.List;
 import java.util.concurrent.Executor;
 
 import net.sf.briar.BriarTestCase;
+import net.sf.briar.TestFileUtils;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.ContactId;
+import net.sf.briar.api.os.FileUtils;
 import net.sf.briar.api.plugins.simplex.SimplexPluginCallback;
 import net.sf.briar.api.plugins.simplex.SimplexTransportWriter;
 import net.sf.briar.plugins.ImmediateExecutor;
@@ -29,6 +31,7 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 
 	private final File testDir = TestUtils.getTestDirectory();
 	private final ContactId contactId = new ContactId(234);
+	private final FileUtils fileUtils = new TestFileUtils();
 
 	@Before
 	public void setUp() {
@@ -55,7 +58,7 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 		}});
 
 		RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
-				callback, finder, monitor, MAX_FRAME_LENGTH, 0);
+				fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0);
 		plugin.start();
 
 		assertNull(plugin.createWriter(contactId));
@@ -90,7 +93,7 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 		}});
 
 		RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
-				callback, finder, monitor, MAX_FRAME_LENGTH, 0);
+				fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0);
 		plugin.start();
 
 		assertNull(plugin.createWriter(contactId));
@@ -127,7 +130,7 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 		}});
 
 		RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
-				callback, finder, monitor, MAX_FRAME_LENGTH, 0);
+				fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0);
 		plugin.start();
 
 		assertNull(plugin.createWriter(contactId));
@@ -166,7 +169,7 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 		}});
 
 		RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
-				callback, finder, monitor, MAX_FRAME_LENGTH, 0);
+				fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0);
 		plugin.start();
 
 		assertNull(plugin.createWriter(contactId));
@@ -205,7 +208,7 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 		}});
 
 		RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
-				callback, finder, monitor, MAX_FRAME_LENGTH, 0);
+				fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0);
 		plugin.start();
 
 		assertNotNull(plugin.createWriter(contactId));
@@ -248,7 +251,7 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 		}});
 
 		RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
-				callback, finder, monitor, MAX_FRAME_LENGTH, 0);
+				fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0);
 		plugin.start();
 
 		SimplexTransportWriter writer = plugin.createWriter(contactId);
@@ -287,7 +290,7 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 		}});
 
 		RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
-				callback, finder, monitor, MAX_FRAME_LENGTH, 0);
+				fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0);
 		plugin.start();
 
 		plugin.driveInserted(testDir);
@@ -307,7 +310,7 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 				context.mock(RemovableDriveMonitor.class);
 
 		RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
-				callback, finder, monitor, MAX_FRAME_LENGTH, 0);
+				fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0);
 
 		assertFalse(plugin.isPossibleConnectionFilename("abcdefg.dat"));
 		assertFalse(plugin.isPossibleConnectionFilename("abcdefghi.dat"));
@@ -335,7 +338,7 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 		}});
 
 		RemovableDrivePlugin plugin = new RemovableDrivePlugin(
-				new ImmediateExecutor(), callback, finder, monitor,
+				new ImmediateExecutor(), fileUtils, callback, finder, monitor,
 				MAX_FRAME_LENGTH, 0);
 		plugin.start();
 
diff --git a/briar-tests/src/net/sf/briar/util/FileUtilsTest.java b/briar-tests/src/net/sf/briar/util/FileUtilsTest.java
deleted file mode 100644
index 24f1ff894133f4a1a6a686c84e0d8aaa74496a4a..0000000000000000000000000000000000000000
--- a/briar-tests/src/net/sf/briar/util/FileUtilsTest.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package net.sf.briar.util;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Scanner;
-
-import net.sf.briar.BriarTestCase;
-import net.sf.briar.TestUtils;
-import net.sf.briar.util.FileUtils.Callback;
-
-import org.jmock.Expectations;
-import org.jmock.Mockery;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-public class FileUtilsTest extends BriarTestCase {
-
-	private final File testDir = TestUtils.getTestDirectory();
-
-	@Before
-	public void setUp() {
-		testDir.mkdirs();
-	}
-
-	@Test
-	public void testCreateTempFile() throws IOException {
-		File temp = FileUtils.createTempFile();
-		assertTrue(temp.exists());
-		assertTrue(temp.isFile());
-		assertEquals(0, temp.length());
-		temp.delete();
-	}
-
-	@Test
-	public void testCopy() throws IOException {
-		File src = new File(testDir, "src");
-		File dest = new File(testDir, "dest");
-		TestUtils.createFile(src, "Foo bar\r\nBar foo\r\n");
-		long length = src.length();
-
-		FileUtils.copy(src, dest);
-
-		assertEquals(length, dest.length());
-		Scanner in = new Scanner(dest);
-		assertTrue(in.hasNextLine());
-		assertEquals("Foo bar", in.nextLine());
-		assertTrue(in.hasNextLine());
-		assertEquals("Bar foo", in.nextLine());
-		assertFalse(in.hasNext());
-		in.close();
-	}
-
-	@Test
-	public void testCopyFromStream() throws IOException {
-		File src = new File(testDir, "src");
-		File dest = new File(testDir, "dest");
-		TestUtils.createFile(src, "Foo bar\r\nBar foo\r\n");
-		long length = src.length();
-		InputStream is = new FileInputStream(src);
-		is.skip(4);
-
-		FileUtils.copy(is, dest);
-
-		assertEquals(length - 4, dest.length());
-		Scanner in = new Scanner(dest);
-		assertTrue(in.hasNextLine());
-		assertEquals("bar", in.nextLine());
-		assertTrue(in.hasNextLine());
-		assertEquals("Bar foo", in.nextLine());
-		assertFalse(in.hasNext());
-		in.close();
-	}
-
-	@Test
-	public void testCopyRecursively() throws IOException {
-		final File dest1 = new File(testDir, "dest/abc/def/1");
-		final File dest2 = new File(testDir, "dest/abc/def/2");
-		final File dest3 = new File(testDir, "dest/abc/3");
-		Mockery context = new Mockery();
-		final Callback callback = context.mock(Callback.class);
-		context.checking(new Expectations() {{
-			oneOf(callback).processingFile(dest1);
-			oneOf(callback).processingFile(dest2);
-			oneOf(callback).processingFile(dest3);
-		}});
-
-		copyRecursively(callback);
-
-		context.assertIsSatisfied();
-	}
-
-	@Test
-	public void testCopyRecursivelyNoCallback() throws IOException {
-		copyRecursively(null);
-	}
-
-	private void copyRecursively(Callback callback) throws IOException {
-		TestUtils.createFile(new File(testDir, "abc/def/1"), "one one one");
-		TestUtils.createFile(new File(testDir, "abc/def/2"), "two two two");
-		TestUtils.createFile(new File(testDir, "abc/3"), "three three three");
-
-		File dest = new File(testDir, "dest");
-		dest.mkdir();
-
-		FileUtils.copyRecursively(new File(testDir, "abc"), dest, callback);
-
-		File dest1 = new File(testDir, "dest/abc/def/1");
-		assertTrue(dest1.exists());
-		assertTrue(dest1.isFile());
-		assertEquals("one one one".length(), dest1.length());
-		File dest2 = new File(testDir, "dest/abc/def/2");
-		assertTrue(dest2.exists());
-		assertTrue(dest2.isFile());
-		assertEquals("two two two".length(), dest2.length());
-		File dest3 = new File(testDir, "dest/abc/3");
-		assertTrue(dest3.exists());
-		assertTrue(dest3.isFile());
-		assertEquals("three three three".length(), dest3.length());
-	}
-
-	@Test
-	public void testDeleteFile() throws IOException {
-		File foo = new File(testDir, "foo");
-		foo.createNewFile();
-		assertTrue(foo.exists());
-
-		FileUtils.delete(foo);
-
-		assertFalse(foo.exists());
-	}
-
-	@Test
-	public void testDeleteDirectory() throws IOException {
-		File f1 = new File(testDir, "abc/def/1");
-		File f2 = new File(testDir, "abc/def/2");
-		File f3 = new File(testDir, "abc/3");
-		File abc = new File(testDir, "abc");
-		File def = new File(testDir, "abc/def");
-		TestUtils.createFile(f1, "one one one");
-		TestUtils.createFile(f2, "two two two");
-		TestUtils.createFile(f3, "three three three");
-
-		assertTrue(f1.exists());
-		assertTrue(f2.exists());
-		assertTrue(f3.exists());
-		assertTrue(abc.exists());
-		assertTrue(def.exists());
-
-		FileUtils.delete(def);
-
-		assertFalse(f1.exists());
-		assertFalse(f2.exists());
-		assertTrue(f3.exists());
-		assertTrue(abc.exists());
-		assertFalse(def.exists());
-	}
-
-	@After
-	public void tearDown() {
-		TestUtils.deleteTestDirectory(testDir);
-	}
-}