From 6830861346d792ff71f9e6705d0bba934b6a4a1f Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Fri, 5 Dec 2014 14:40:28 +0100 Subject: [PATCH] webdav mounting on windows --- .../org/cryptomator/webdav/WebDAVServer.java | 17 ++++++- .../org/cryptomator/ui/AccessController.java | 19 +++---- .../cryptomator/ui/util/WebDavMounter.java | 49 +++++++++++++------ 3 files changed, 59 insertions(+), 26 deletions(-) diff --git a/main/core/src/main/java/org/cryptomator/webdav/WebDAVServer.java b/main/core/src/main/java/org/cryptomator/webdav/WebDAVServer.java index 0e819d50f..338caa1d7 100644 --- a/main/core/src/main/java/org/cryptomator/webdav/WebDAVServer.java +++ b/main/core/src/main/java/org/cryptomator/webdav/WebDAVServer.java @@ -8,6 +8,9 @@ ******************************************************************************/ package org.cryptomator.webdav; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + import org.cryptomator.crypto.Cryptor; import org.cryptomator.webdav.jackrabbit.WebDavServlet; import org.eclipse.jetty.server.Connector; @@ -15,6 +18,8 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.eclipse.jetty.util.thread.ThreadPool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,7 +27,17 @@ public final class WebDAVServer { private static final Logger LOG = LoggerFactory.getLogger(WebDAVServer.class); private static final String LOCALHOST = "127.0.0.1"; - private final Server server = new Server(); + private static final int MAX_PENDING_REQUESTS = 200; + private static final int MAX_THREADS = 4; + private static final int MIN_THREADS = 2; + private static final int THREAD_IDLE_SECONDS = 20; + private final Server server; + + public WebDAVServer() { + final BlockingQueue queue = new LinkedBlockingQueue<>(MAX_PENDING_REQUESTS); + final ThreadPool tp = new QueuedThreadPool(MAX_THREADS, MIN_THREADS, THREAD_IDLE_SECONDS, queue); + server = new Server(tp); + } /** * @param workDir Path of encrypted folder. diff --git a/main/ui/src/main/java/org/cryptomator/ui/AccessController.java b/main/ui/src/main/java/org/cryptomator/ui/AccessController.java index 75d09fc35..4b7f9c6e0 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/AccessController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/AccessController.java @@ -15,7 +15,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.ResourceBundle; -import java.util.concurrent.atomic.AtomicInteger; import javafx.event.ActionEvent; import javafx.fxml.FXML; @@ -39,12 +38,11 @@ import org.slf4j.LoggerFactory; public class AccessController implements Initializable { private static final Logger LOG = LoggerFactory.getLogger(AccessController.class); - private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); private final Aes256Cryptor cryptor = new Aes256Cryptor(); private final WebDAVServer server = new WebDAVServer(); - private final int id = ID_GENERATOR.getAndIncrement(); private ResourceBundle rb; + private String unmountCmd; @FXML private GridPane rootPane; @@ -91,7 +89,7 @@ public class AccessController implements Initializable { final int webdavPort = server.start(settings.getWebdavWorkDir(), cryptor); if (webdavPort > 0) { try { - WebDavMounter.mount(webdavPort, id); + unmountCmd = WebDavMounter.mount(webdavPort); MainApplication.addShutdownTask(this::tryStop); } catch (CommandFailedException e) { messageLabel.setText(String.format(rb.getString("access.messageLabel.mountFailed"), webdavPort)); @@ -101,14 +99,13 @@ public class AccessController implements Initializable { } public void tryStop() { - try { - if (server != null && server.isRunning()) { - WebDavMounter.unmount(id, 5); - server.stop(); + if (server != null && server.isRunning()) { + try { + WebDavMounter.unmount(unmountCmd); + } catch (CommandFailedException e) { + LOG.warn("Unmounting WebDAV share failed.", e); } - } catch (CommandFailedException e) { - LOG.warn("Unmounting WebDAV share failed.", e); - } finally { + server.stop(); cryptor.swipeSensitiveData(); } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/WebDavMounter.java b/main/ui/src/main/java/org/cryptomator/ui/util/WebDavMounter.java index 3aac63a84..b12426834 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/WebDavMounter.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/WebDavMounter.java @@ -10,6 +10,8 @@ package org.cryptomator.ui.util; import java.io.IOException; import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.SystemUtils; @@ -19,35 +21,54 @@ import org.slf4j.LoggerFactory; public final class WebDavMounter { private static final Logger LOG = LoggerFactory.getLogger(WebDavMounter.class); - private static final int CMD_DEFAULT_TIMEOUT = 1; + private static final int CMD_DEFAULT_TIMEOUT = 3; + private static final Pattern WIN_MOUNT_DRIVELETTER_PATTERN = Pattern.compile("\\s*[A-Z]:\\s*"); private WebDavMounter() { throw new IllegalStateException("not instantiable."); } - - public static synchronized void mount(int localPort, int uniqueId) throws CommandFailedException { + + /** + * @return Unmount Command + */ + public static synchronized String mount(int localPort) throws CommandFailedException { if (SystemUtils.IS_OS_MAC_OSX) { - exec("mkdir /Volumes/Cryptomator" + uniqueId, CMD_DEFAULT_TIMEOUT); - exec("mount_webdav -S -v Cryptomator localhost:" + localPort + " /Volumes/Cryptomator" + uniqueId, CMD_DEFAULT_TIMEOUT); - exec("open /Volumes/Cryptomator" + uniqueId, CMD_DEFAULT_TIMEOUT); + exec("mkdir /Volumes/Cryptomator" + localPort, CMD_DEFAULT_TIMEOUT); + exec("mount_webdav -S -v Cryptomator localhost:" + localPort + " /Volumes/Cryptomator" + localPort, CMD_DEFAULT_TIMEOUT); + exec("open /Volumes/Cryptomator" + localPort, CMD_DEFAULT_TIMEOUT); + return "umount /Volumes/Cryptomator" + localPort; + } else if (SystemUtils.IS_OS_WINDOWS) { + final String result = exec("net use * http://127.0.0.1:" + localPort + " /persistent:no", CMD_DEFAULT_TIMEOUT); + final Matcher matcher = WIN_MOUNT_DRIVELETTER_PATTERN.matcher(result); + if (matcher.find()) { + final String driveLetter = matcher.group(); + return "net use " + driveLetter + " /delete"; + } + } + return null; + } + + public static void unmount(String command) throws CommandFailedException { + if (command != null) { + exec(command, CMD_DEFAULT_TIMEOUT); } } - public static synchronized void unmount(int uniqueId, int timeout) throws CommandFailedException { - if (SystemUtils.IS_OS_MAC_OSX) { - exec("umount /Volumes/Cryptomator" + uniqueId, timeout); - } - } - - private static void exec(String cmd, int timoutSeconds) throws CommandFailedException { + private static String exec(String cmd, int timoutSeconds) throws CommandFailedException { try { - final Process proc = Runtime.getRuntime().exec(new String[] {"/bin/sh", "-c", cmd}); + final Process proc; + if (SystemUtils.IS_OS_WINDOWS) { + proc = Runtime.getRuntime().exec(new String[]{"cmd", "/C", cmd}); + } else { + proc = Runtime.getRuntime().exec(new String[] {"/bin/sh", "-c", cmd}); + } if (proc.waitFor(timoutSeconds, TimeUnit.SECONDS)) { proc.destroy(); } if (proc.exitValue() != 0) { throw new CommandFailedException(IOUtils.toString(proc.getErrorStream())); } + return IOUtils.toString(proc.getInputStream()); } catch (IOException | InterruptedException | IllegalThreadStateException e) { LOG.error("Command execution failed.", e); throw new CommandFailedException(e);