diff --git a/pom.xml b/pom.xml
index af59360..6b4d59e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,6 +12,7 @@
1.0.11
1.4
1.2.3
+ 1.2.4
11
UTF-8
@@ -46,6 +47,11 @@
webdav-nio-adapter
${webdav-nio.version}
+
+ org.cryptomator
+ fuse-nio-adapter
+ ${fuse-nio.version}
+
diff --git a/src/main/java/org/cryptomator/cli/Args.java b/src/main/java/org/cryptomator/cli/Args.java
index 13de342..492310b 100644
--- a/src/main/java/org/cryptomator/cli/Args.java
+++ b/src/main/java/org/cryptomator/cli/Args.java
@@ -8,6 +8,7 @@
*******************************************************************************/
package org.cryptomator.cli;
+import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
@@ -71,22 +72,43 @@ public class Args {
.valueSeparator() //
.hasArgs() //
.build());
+ OPTIONS.addOption(Option.builder() //
+ .longOpt("fusemount") //
+ .argName("mount point") //
+ .desc("Format must be vaultName=mountpoint") //
+ .valueSeparator() //
+ .hasArgs() //
+ .build());
}
private final String bindAddr;
private final int port;
+ private final boolean hasValidWebDavConfig;
private final Properties vaultPaths;
private final Properties vaultPasswords;
private final Properties vaultPasswordFiles;
private final Map passwordStrategies;
+ private final Properties fuseMountPoints;
public Args(CommandLine commandLine) throws ParseException {
- this.bindAddr = commandLine.getOptionValue("bind", "localhost");
- this.port = Integer.parseInt(commandLine.getOptionValue("port", "0"));
+ if (commandLine.hasOption("bind") && commandLine.hasOption("port")) {
+ hasValidWebDavConfig = true;
+ this.bindAddr = commandLine.getOptionValue("bind", "localhost");
+ this.port = Integer.parseInt(commandLine.getOptionValue("port", "0"));
+ } else {
+ hasValidWebDavConfig = false;
+ this.bindAddr = "";
+ this.port = -1;
+ }
this.vaultPaths = commandLine.getOptionProperties("vault");
this.vaultPasswords = commandLine.getOptionProperties("password");
this.vaultPasswordFiles = commandLine.getOptionProperties("passwordfile");
this.passwordStrategies = new HashMap<>();
+ this.fuseMountPoints = commandLine.getOptionProperties("fusemount");
+ }
+
+ public boolean hasValidWebDavConf() {
+ return hasValidWebDavConfig;
}
public String getBindAddr() {
@@ -118,15 +140,10 @@ public PasswordStrategy addPasswortStrategy(final String vaultName) {
PasswordStrategy passwordStrategy = new PasswordFromStdInputStrategy(vaultName);
if (vaultPasswords.getProperty(vaultName) != null) {
- passwordStrategy = new PasswordFromPropertyStrategy(
- vaultName,
- vaultPasswords.getProperty(vaultName)
- );
+ passwordStrategy = new PasswordFromPropertyStrategy(vaultName, vaultPasswords.getProperty(vaultName));
} else if (vaultPasswordFiles.getProperty(vaultName) != null) {
- passwordStrategy = new PasswordFromFileStrategy(
- vaultName,
- Paths.get(vaultPasswordFiles.getProperty(vaultName))
- );
+ passwordStrategy = new PasswordFromFileStrategy(vaultName,
+ Paths.get(vaultPasswordFiles.getProperty(vaultName)));
}
this.passwordStrategies.put(vaultName, passwordStrategy);
@@ -136,4 +153,13 @@ public PasswordStrategy addPasswortStrategy(final String vaultName) {
public PasswordStrategy getPasswordStrategy(final String vaultName) {
return passwordStrategies.get(vaultName);
}
+
+ public Path getFuseMountPoint(String vaultName) {
+ String mountPoint = fuseMountPoints.getProperty(vaultName);
+ if (mountPoint == null) {
+ return null;
+ }
+ Path mountPointPath = Paths.get(mountPoint);
+ return mountPointPath;
+ }
}
diff --git a/src/main/java/org/cryptomator/cli/CryptomatorCli.java b/src/main/java/org/cryptomator/cli/CryptomatorCli.java
index ab7940b..d2cc903 100644
--- a/src/main/java/org/cryptomator/cli/CryptomatorCli.java
+++ b/src/main/java/org/cryptomator/cli/CryptomatorCli.java
@@ -8,17 +8,20 @@
*******************************************************************************/
package org.cryptomator.cli;
+import org.cryptomator.cli.frontend.FuseMount;
+import org.cryptomator.cli.frontend.WebDav;
+
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Optional;
import java.util.Set;
import org.apache.commons.cli.ParseException;
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
-import org.cryptomator.frontend.webdav.WebDavServer;
-import org.cryptomator.frontend.webdav.servlet.WebDavServletController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -42,7 +45,7 @@ public static void main(String[] rawArgs) throws IOException {
private static void validate(Args args) throws IllegalArgumentException {
Set vaultNames = args.getVaultNames();
- if (args.getPort() < 0 || args.getPort() > 65536) {
+ if (args.hasValidWebDavConf() && (args.getPort() < 0 || args.getPort() > 65536)) {
throw new IllegalArgumentException("Invalid WebDAV Port.");
}
@@ -56,28 +59,45 @@ private static void validate(Args args) throws IllegalArgumentException {
throw new IllegalArgumentException("Not a directory: " + vaultPath);
}
args.addPasswortStrategy(vaultName).validate();
+
+ Path mountPoint = args.getFuseMountPoint(vaultName);
+ if (mountPoint != null && !Files.isDirectory(mountPoint)) {
+ throw new IllegalArgumentException("Fuse mount point does not exist: " + mountPoint);
+ }
}
}
private static void startup(Args args) throws IOException {
- WebDavServer server = WebDavServer.create();
- server.bind(args.getBindAddr(), args.getPort());
- server.start();
+ Optional server = initWebDavServer(args);
+ ArrayList mounts = new ArrayList<>();
for (String vaultName : args.getVaultNames()) {
Path vaultPath = Paths.get(args.getVaultPath(vaultName));
LOG.info("Unlocking vault \"{}\" located at {}", vaultName, vaultPath);
String vaultPassword = args.getPasswordStrategy(vaultName).password();
- CryptoFileSystemProperties properties = CryptoFileSystemProperties.cryptoFileSystemProperties().withPassphrase(vaultPassword).build();
+ CryptoFileSystemProperties properties = CryptoFileSystemProperties.cryptoFileSystemProperties()
+ .withPassphrase(vaultPassword).build();
Path vaultRoot = CryptoFileSystemProvider.newFileSystem(vaultPath, properties).getPath("/");
- WebDavServletController servlet = server.createWebDavServlet(vaultRoot, vaultName);
- servlet.start();
+
+ Path fuseMountPoint = args.getFuseMountPoint(vaultName);
+ if (fuseMountPoint != null) {
+ FuseMount newMount = new FuseMount(vaultRoot, fuseMountPoint);
+ if (newMount.mount()) {
+ mounts.add(newMount);
+ }
+ }
+
+ server.ifPresent(serv -> serv.addServlet(vaultRoot, vaultName));
}
waitForShutdown(() -> {
LOG.info("Shutting down...");
try {
- server.stop();
+ server.ifPresent(serv -> serv.stop());
+
+ for (FuseMount mount : mounts) {
+ mount.unmount();
+ }
LOG.info("Shutdown successful.");
} catch (Throwable e) {
LOG.error("Error during shutdown", e);
@@ -85,9 +105,23 @@ private static void startup(Args args) throws IOException {
});
}
+ private static Optional initWebDavServer(Args args) {
+ Optional server = Optional.empty();
+ if (args.hasValidWebDavConf()) {
+ server = Optional.of(new WebDav(args.getBindAddr(), args.getPort()));
+ }
+ return server;
+ }
+
private static void waitForShutdown(Runnable runnable) {
Runtime.getRuntime().addShutdownHook(new Thread(runnable));
- LOG.info("Server started. Press Ctrl+C to terminate.");
+ LOG.info("Press Ctrl+C to terminate.");
+ try {
+ while (true) {
+ System.in.read();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
}
-
}
diff --git a/src/main/java/org/cryptomator/cli/frontend/FuseMount.java b/src/main/java/org/cryptomator/cli/frontend/FuseMount.java
new file mode 100644
index 0000000..976085d
--- /dev/null
+++ b/src/main/java/org/cryptomator/cli/frontend/FuseMount.java
@@ -0,0 +1,63 @@
+package org.cryptomator.cli.frontend;
+
+import java.nio.file.Path;
+
+import org.cryptomator.frontend.fuse.mount.CommandFailedException;
+import org.cryptomator.frontend.fuse.mount.EnvironmentVariables;
+import org.cryptomator.frontend.fuse.mount.FuseMountFactory;
+import org.cryptomator.frontend.fuse.mount.Mount;
+import org.cryptomator.frontend.fuse.mount.Mounter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FuseMount {
+ private static final Logger LOG = LoggerFactory.getLogger(FuseMount.class);
+
+ private Path vaultRoot;
+ private Path mountPoint;
+ private Mount mnt;
+
+ public FuseMount(Path vaultRoot, Path mountPoint) {
+ this.vaultRoot = vaultRoot;
+ this.mountPoint = mountPoint;
+ this.mnt = null;
+ }
+
+ public boolean mount() {
+ if (mnt != null) {
+ LOG.info("Already mounted to {}", mountPoint);
+ return false;
+ }
+
+ try {
+ Mounter mounter = FuseMountFactory.getMounter();
+ EnvironmentVariables envVars = EnvironmentVariables.create().withFlags(mounter.defaultMountFlags())
+ .withMountPoint(mountPoint).build();
+ mnt = mounter.mount(vaultRoot, envVars);
+ LOG.info("Mounted to {}", mountPoint);
+ } catch (CommandFailedException e) {
+ LOG.error("Can't mount: {}, error: {}", mountPoint, e.getMessage());
+ return false;
+ }
+ return true;
+ }
+
+ public void unmount() {
+ try {
+ mnt.unmount();
+ LOG.info("Unmounted {}", mountPoint);
+ } catch (CommandFailedException e) {
+ LOG.error("Can't unmount gracefully: {}. Force unmount.", e.getMessage());
+ forceUnmount();
+ }
+ }
+
+ private void forceUnmount() {
+ try {
+ mnt.unmountForced();
+ LOG.info("Unmounted {}", mountPoint);
+ } catch (CommandFailedException e) {
+ LOG.error("Force unmount failed: {}", e.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/org/cryptomator/cli/frontend/WebDav.java b/src/main/java/org/cryptomator/cli/frontend/WebDav.java
new file mode 100644
index 0000000..9af6a31
--- /dev/null
+++ b/src/main/java/org/cryptomator/cli/frontend/WebDav.java
@@ -0,0 +1,38 @@
+package org.cryptomator.cli.frontend;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+
+import org.cryptomator.frontend.webdav.WebDavServer;
+import org.cryptomator.frontend.webdav.servlet.WebDavServletController;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebDav {
+ private static final Logger LOG = LoggerFactory.getLogger(WebDav.class);
+
+ private final WebDavServer server;
+ private ArrayList servlets;
+
+ public WebDav(String bindAddr, int port) {
+ servlets = new ArrayList<>();
+ server = WebDavServer.create();
+ server.bind(bindAddr, port);
+ server.start();
+ LOG.info("WebDAV server started: {}:{}", bindAddr, port);
+ }
+
+ public void stop() {
+ for (WebDavServletController controller : servlets) {
+ controller.stop();
+ }
+ server.stop();
+ }
+
+ public void addServlet(Path vaultRoot, String vaultName) {
+ WebDavServletController servlet = server.createWebDavServlet(vaultRoot, vaultName);
+ servlets.add(servlet);
+ servlet.start();
+ }
+}