mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 13:19:52 +01:00
Removable drive finders for Windows, Mac and Linux (untested).
This commit is contained in:
121
components/net/sf/briar/plugins/file/FilePlugin.java
Normal file
121
components/net/sf/briar/plugins/file/FilePlugin.java
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
package net.sf.briar.plugins.file;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileSystemUtils;
|
||||||
|
|
||||||
|
import net.sf.briar.api.ContactId;
|
||||||
|
import net.sf.briar.api.TransportId;
|
||||||
|
import net.sf.briar.api.transport.InvalidConfigException;
|
||||||
|
import net.sf.briar.api.transport.InvalidTransportException;
|
||||||
|
import net.sf.briar.api.transport.TransportConstants;
|
||||||
|
import net.sf.briar.api.transport.batch.BatchTransportCallback;
|
||||||
|
import net.sf.briar.api.transport.batch.BatchTransportPlugin;
|
||||||
|
import net.sf.briar.api.transport.batch.BatchTransportReader;
|
||||||
|
import net.sf.briar.api.transport.batch.BatchTransportWriter;
|
||||||
|
|
||||||
|
abstract class FilePlugin implements BatchTransportPlugin {
|
||||||
|
|
||||||
|
public static final int TRANSPORT_ID = 0;
|
||||||
|
|
||||||
|
private static final TransportId id = new TransportId(TRANSPORT_ID);
|
||||||
|
|
||||||
|
private boolean started = false;
|
||||||
|
protected Map<String, String> localProperties = null;
|
||||||
|
protected Map<ContactId, Map<String, String>> remoteProperties = null;
|
||||||
|
protected Map<String, String> config = null;
|
||||||
|
protected BatchTransportCallback callback = null;
|
||||||
|
|
||||||
|
protected abstract File chooseOutputDirectory();
|
||||||
|
protected abstract void writerFinished(File f);
|
||||||
|
|
||||||
|
public TransportId getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void start(Map<String, String> localProperties,
|
||||||
|
Map<ContactId, Map<String, String>> remoteProperties,
|
||||||
|
Map<String, String> config, BatchTransportCallback callback)
|
||||||
|
throws InvalidTransportException, InvalidConfigException {
|
||||||
|
if(started) throw new IllegalStateException();
|
||||||
|
started = true;
|
||||||
|
this.localProperties = localProperties;
|
||||||
|
this.remoteProperties = remoteProperties;
|
||||||
|
this.config = config;
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void stop() {
|
||||||
|
if(!started) throw new IllegalStateException();
|
||||||
|
started = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void setLocalProperties(Map<String, String> properties)
|
||||||
|
throws InvalidTransportException {
|
||||||
|
if(!started) throw new IllegalStateException();
|
||||||
|
localProperties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void setRemoteProperties(ContactId c,
|
||||||
|
Map<String, String> properties)
|
||||||
|
throws InvalidTransportException {
|
||||||
|
if(!started) throw new IllegalStateException();
|
||||||
|
remoteProperties.put(c, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void setConfig(Map<String, String> config)
|
||||||
|
throws InvalidConfigException {
|
||||||
|
if(!started) throw new IllegalStateException();
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldPoll() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPollingInterval() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void poll() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BatchTransportReader createReader(ContactId c) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BatchTransportWriter createWriter(ContactId c) {
|
||||||
|
if(!started) throw new IllegalStateException();
|
||||||
|
File dir = chooseOutputDirectory();
|
||||||
|
if(dir == null) return null;
|
||||||
|
if(!dir.exists()) return null;
|
||||||
|
if(!dir.isDirectory()) return null;
|
||||||
|
File f = new File(dir, createFilename());
|
||||||
|
try {
|
||||||
|
long capacity = getCapacity(f.getAbsolutePath());
|
||||||
|
if(capacity < TransportConstants.MIN_CONNECTION_LENGTH) return null;
|
||||||
|
OutputStream out = new FileOutputStream(f);
|
||||||
|
return new FileTransportWriter(f, out, capacity, this);
|
||||||
|
} catch(IOException e) {
|
||||||
|
f.delete();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String createFilename() {
|
||||||
|
StringBuilder s = new StringBuilder(12);
|
||||||
|
for(int i = 0; i < 8; i++) s.append((char) ('a' + Math.random() * 26));
|
||||||
|
s.append(".dat");
|
||||||
|
System.out.println(s);
|
||||||
|
return s.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long getCapacity(String path) throws IOException {
|
||||||
|
return FileSystemUtils.freeSpaceKb(path) * 1024L;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package net.sf.briar.plugins.file;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import net.sf.briar.api.transport.batch.BatchTransportWriter;
|
||||||
|
|
||||||
|
class FileTransportWriter implements BatchTransportWriter {
|
||||||
|
|
||||||
|
private final File file;
|
||||||
|
private final OutputStream out;
|
||||||
|
private final long capacity;
|
||||||
|
private final FilePlugin plugin;
|
||||||
|
|
||||||
|
private boolean streamInUse = false;
|
||||||
|
|
||||||
|
FileTransportWriter(File file, OutputStream out, long capacity,
|
||||||
|
FilePlugin plugin) {
|
||||||
|
this.file = file;
|
||||||
|
this.out = out;
|
||||||
|
this.capacity = capacity;
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCapacity() {
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputStream getOutputStream() {
|
||||||
|
streamInUse = true;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finish() {
|
||||||
|
streamInUse = false;
|
||||||
|
plugin.writerFinished(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose() throws IOException {
|
||||||
|
if(streamInUse) out.close();
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package net.sf.briar.plugins.file;
|
||||||
|
|
||||||
|
class LinuxRemovableDriveFinder extends UnixRemovableDriveFinder {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getMountCommand() {
|
||||||
|
return "/bin/mount";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String parseMountPoint(String line) {
|
||||||
|
// The format is "/dev/foo on /bar/baz type bam (opt1,opt2)"
|
||||||
|
line = line.replaceFirst("^/dev/[^ ]+ on ", "");
|
||||||
|
return line.replaceFirst(" type [^ ]+ \\([^)]+\\)$", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isRemovableDriveMountPoint(String path) {
|
||||||
|
return path.startsWith("/mnt/") || path.startsWith("/media/");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package net.sf.briar.plugins.file;
|
||||||
|
|
||||||
|
class MacRemovableDriveFinder extends UnixRemovableDriveFinder {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getMountCommand() {
|
||||||
|
return "/sbin/mount";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String parseMountPoint(String line) {
|
||||||
|
// The format is "/dev/foo on /bar/baz (opt1, opt2)"
|
||||||
|
line = line.replaceFirst("^/dev/[^ ]+ on ", "");
|
||||||
|
return line.replaceFirst(" \\([^)]+\\)$", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isRemovableDriveMountPoint(String path) {
|
||||||
|
return path.startsWith("/Volumes/");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package net.sf.briar.plugins.file;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
interface RemovableDriveFinder {
|
||||||
|
|
||||||
|
List<File> findRemovableDrives() throws IOException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package net.sf.briar.plugins.file;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.sf.briar.util.OsUtils;
|
||||||
|
|
||||||
|
class RemovableDriveFinderImpl implements RemovableDriveFinder {
|
||||||
|
|
||||||
|
private final LinuxRemovableDriveFinder linux =
|
||||||
|
new LinuxRemovableDriveFinder();
|
||||||
|
private final MacRemovableDriveFinder mac =
|
||||||
|
new MacRemovableDriveFinder();
|
||||||
|
private final WindowsRemovableDriveFinder windows =
|
||||||
|
new WindowsRemovableDriveFinder();
|
||||||
|
|
||||||
|
public List<File> findRemovableDrives() throws IOException {
|
||||||
|
if(OsUtils.isLinux()) return linux.findRemovableDrives();
|
||||||
|
else if(OsUtils.isMac()) return mac.findRemovableDrives();
|
||||||
|
else if(OsUtils.isWindows()) return windows.findRemovableDrives();
|
||||||
|
else return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package net.sf.briar.plugins.file;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class RemovableDrivePlugin extends FilePlugin {
|
||||||
|
|
||||||
|
private final RemovableDriveFinder finder;
|
||||||
|
|
||||||
|
RemovableDrivePlugin(RemovableDriveFinder finder) {
|
||||||
|
this.finder = finder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected File chooseOutputDirectory() {
|
||||||
|
try {
|
||||||
|
List<File> drives = finder.findRemovableDrives();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
int i = callback.showChoice("REMOVABLE_DRIVE_CHOOSE_DRIVE", paths);
|
||||||
|
if(i == -1) return null;
|
||||||
|
return drives.get(i);
|
||||||
|
} catch(IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void writerFinished(File f) {
|
||||||
|
callback.showMessage("REMOVABLE_DRIVE_WRITE_FINISHED");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package net.sf.briar.plugins.file;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
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 {
|
||||||
|
List<File> drives = new ArrayList<File>();
|
||||||
|
Process p = new ProcessBuilder(getMountCommand()).start();
|
||||||
|
Scanner s = new Scanner(p.getInputStream(), "UTF-8");
|
||||||
|
try {
|
||||||
|
while(s.hasNextLine()) {
|
||||||
|
String line = s.nextLine();
|
||||||
|
String[] tokens = line.split(" ");
|
||||||
|
if(tokens.length < 3) continue;
|
||||||
|
// The general format is "/dev/foo on /bar/baz ..."
|
||||||
|
if(tokens[0].startsWith("/dev/") && tokens[1].equals("on")) {
|
||||||
|
// The path may contain spaces so we can't use tokens[2]
|
||||||
|
String path = parseMountPoint(line);
|
||||||
|
if(isRemovableDriveMountPoint(path)) {
|
||||||
|
File f = new File(path);
|
||||||
|
if(f.exists() && f.isDirectory()) drives.add(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
return drives;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package net.sf.briar.plugins.file;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.platform.win32.Kernel32;
|
||||||
|
|
||||||
|
class WindowsRemovableDriveFinder implements RemovableDriveFinder {
|
||||||
|
|
||||||
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa364939.aspx
|
||||||
|
private static final int DRIVE_REMOVABLE = 2;
|
||||||
|
|
||||||
|
public List<File> findRemovableDrives() throws IOException {
|
||||||
|
File[] roots = File.listRoots();
|
||||||
|
if(roots == null) throw new IOException();
|
||||||
|
List<File> drives = new ArrayList<File>();
|
||||||
|
for(File root : roots) {
|
||||||
|
try {
|
||||||
|
int type = Kernel32.INSTANCE.GetDriveType(root.getPath());
|
||||||
|
if(type == DRIVE_REMOVABLE) drives.add(root);
|
||||||
|
} catch(RuntimeException e) {
|
||||||
|
throw new IOException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return drives;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
29
test/net/sf/briar/plugins/file/TestFilePlugin.java
Normal file
29
test/net/sf/briar/plugins/file/TestFilePlugin.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user