diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/FuseEnvironment.java b/main/ui/src/main/java/org/cryptomator/ui/model/FuseEnvironment.java new file mode 100644 index 000000000..48c3f0c45 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/model/FuseEnvironment.java @@ -0,0 +1,28 @@ +package org.cryptomator.ui.model; + +import java.nio.file.Path; + +public interface FuseEnvironment { + + void prepare() throws CommandFailedException; + + String[] getMountParameters() throws CommandFailedException; + + Path getFsRootPath(); + + /** + * TODO: implement it in subclasses! + * @throws CommandFailedException + */ + default void revealFsRootInFilesystemManager() throws CommandFailedException { + throw new CommandFailedException("Not implemented."); + } + + void cleanUp(); + + default boolean supportsFuse(){ + return false; + } + + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/FuseNioAdapter.java b/main/ui/src/main/java/org/cryptomator/ui/model/FuseNioAdapter.java index 6abd25955..3467d5cfd 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/FuseNioAdapter.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/FuseNioAdapter.java @@ -1,62 +1,25 @@ package org.cryptomator.ui.model; -import org.cryptomator.common.settings.Settings; -import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.cryptofs.CryptoFileSystem; import org.cryptomator.frontend.fuse.AdapterFactory; -import org.apache.commons.lang3.SystemUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; -import java.io.IOException; -import java.nio.file.DirectoryNotEmptyException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Scanner; -import java.util.concurrent.TimeUnit; @VaultModule.PerVault public class FuseNioAdapter implements NioAdapter { private static final Logger LOG = LoggerFactory.getLogger(FuseNioAdapter.class); - private static final String AUTOASSIGN_DRRIVE_LETTER = "*"; + private final FuseEnvironment fuseEnv; - private enum OS { - WINDOWS, - LINUX, - MAC; - - public static OS getCurrentOS() { - if (SystemUtils.IS_OS_WINDOWS) { - return WINDOWS; - } else if (SystemUtils.IS_OS_MAC) { - return MAC; - } else { - return LINUX; - } - } - - } - - - private final VaultSettings vaultSettings; - private final Settings settings; - private final WindowsDriveLetters windowsDriveLetters; - private final OS os = OS.getCurrentOS(); private org.cryptomator.frontend.fuse.FuseNioAdapter ffs; - private String mountNameAndId; - private String mountURL; private CryptoFileSystem cfs; @Inject - public FuseNioAdapter(VaultSettings vaultSettings, Settings settings, WindowsDriveLetters windowsDriveLetters) { - this.vaultSettings = vaultSettings; - this.settings = settings; - this.windowsDriveLetters = windowsDriveLetters; + public FuseNioAdapter(FuseEnvironment fuseEnv) { + this.fuseEnv = fuseEnv; } @Override @@ -72,97 +35,26 @@ public class FuseNioAdapter implements NioAdapter { */ @Override public void mount() throws CommandFailedException { - ArrayList mountOptions = new ArrayList<>(8); - mountOptions.add(("-oatomic_o_trunc")); - Path path; - try { - switch (os) { - case MAC: - path = Paths.get(vaultSettings.mountPath().get() + vaultSettings.mountName().get()); - createVaultDirIfNotExist(path); - mountOptions.add("-ouid=" + getUIdOrGID("uid")); - mountOptions.add("-ogid=" + getUIdOrGID("gid")); - mountOptions.add("-ovolname=" + vaultSettings.mountName().get()); - mountOptions.add("-oauto_xattr"); - break; - case WINDOWS: - if (vaultSettings.winDriveLetter().get().equals(AUTOASSIGN_DRRIVE_LETTER)) { - if (!windowsDriveLetters.getAvailableDriveLetters().isEmpty()) { - path = Paths.get(windowsDriveLetters.getAvailableDriveLetters().iterator().next() + ":\\"); - } else { - throw new CommandFailedException("No free drive letter to mount."); - } - } else { - path = Paths.get(vaultSettings.winDriveLetter().get() + ":\\"); - } - mountOptions.add("-ouid=-1"); - mountOptions.add("-ogid=-1"); - mountOptions.add("-ovolname=" + vaultSettings.mountName().get()); - mountOptions.add("-oFileInfoTimeout=-1"); - break; - case LINUX: - path = Paths.get(vaultSettings.mountPath().get() + vaultSettings.mountName().get()); - createVaultDirIfNotExist(path); - mountOptions.add("-ouid=" + getUIdOrGID("uid")); - mountOptions.add("-ogid=" + getUIdOrGID("gid")); - mountOptions.add("-oauto_unmount"); - mountOptions.add("-ofsname=CryptoFs"); - break; - default: - throw new IllegalStateException("Not Supported OS."); - } - ffs.mount(path, false, false, mountOptions.toArray(new String[mountOptions.size()])); - mountURL = path.toAbsolutePath().toUri().toURL().toString(); - } catch (Exception e) { + try { + fuseEnv.prepare(); + ffs.mount(fuseEnv.getFsRootPath(), false, false, fuseEnv.getMountParameters()); + } catch (Exception e) { throw new CommandFailedException("Unable to mount Filesystem", e); } } - private void createVaultDirIfNotExist(Path p) throws IOException { - try { - if (Files.exists(p)) { - if (Files.isDirectory(p)) { - if (Files.newDirectoryStream(p).iterator().hasNext()) { - return; - } else { - throw new DirectoryNotEmptyException("Directory not empty."); - } - } - } else { - Files.createDirectory(p); - } - } catch (IOException e) { - throw e; - } - } - - private String getUIdOrGID(String idtype) throws IOException { - String id; - String parameter; - switch (idtype) { - case "uid": - parameter = "-u"; - break; - case "gid": - parameter = "-g"; - break; - default: - throw new IllegalArgumentException("Unkown ID type"); - } - Process getId = new ProcessBuilder("sh", "-c", "id " + parameter).start(); - Scanner s = new Scanner(getId.getInputStream()).useDelimiter("\\A"); - try { - getId.waitFor(1000, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } - id = s.nextLine(); - return id; + /** + * TODO: implement it! + * @throws CommandFailedException + */ + @Override + public void reveal() throws CommandFailedException{ + //fuseEnv.revealFsRootUrlInFilesystemManager(SOMETHING); } @Override public synchronized void unmount() throws CommandFailedException { - if (!(cfs.getStats().pollBytesRead() > 0 || cfs.getStats().pollBytesWritten() > 0)) { + if (cfs.getStats().pollBytesRead() == 0 && cfs.getStats().pollBytesWritten() == 0) { unmountForced(); } else { throw new CommandFailedException("Pending read or write operations."); @@ -176,45 +68,17 @@ public class FuseNioAdapter implements NioAdapter { @Override public void stop() { - switch (os) { - case WINDOWS: - return; - case MAC: - case LINUX: - try { - Files.deleteIfExists(Paths.get(vaultSettings.mountPath().get() + vaultSettings.mountName().get())); - } catch (IOException e) { - LOG.warn("Could not delete mount directory of vault " + vaultSettings.mountName()); - e.printStackTrace(); - } - return; - default: - return; - } - + fuseEnv.cleanUp(); } @Override - public String getFilesystemRootUrl() { - return mountURL; + public String getFsRootUrlString() { + return fuseEnv.getFsRootPath().toUri().toString(); } - /** - * TODO: what should i check here? - */ @Override public boolean isSupported() { - switch (os) { - case LINUX: - return true; - case WINDOWS: - break; - case MAC: - break; - default: - return false; - } - return true; + return fuseEnv.supportsFuse(); } @Override diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/LinuxFuseEnvironment.java b/main/ui/src/main/java/org/cryptomator/ui/model/LinuxFuseEnvironment.java new file mode 100644 index 000000000..b72f378c4 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/model/LinuxFuseEnvironment.java @@ -0,0 +1,118 @@ +package org.cryptomator.ui.model; + +import org.cryptomator.common.settings.VaultSettings; + +import javax.inject.Inject; +import java.io.IOException; +import java.nio.file.DirectoryNotEmptyException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Scanner; +import java.util.concurrent.TimeUnit; + +public class LinuxFuseEnvironment implements FuseEnvironment{ + + private final VaultSettings vaultSettings; + private Path root; + + @Inject + public LinuxFuseEnvironment(VaultSettings vaultSettings){ + this.vaultSettings = vaultSettings; + } + + @Override + public void prepare() throws CommandFailedException { + this.root = Paths.get(vaultSettings.mountPath().get() + vaultSettings.mountName().get()).toAbsolutePath(); + try { + createVaultDirIfNotExist(root); + } catch (IOException e) { + e.printStackTrace(); + throw new CommandFailedException(e); + } + } + + private void createVaultDirIfNotExist(Path p) throws IOException { + try { + if (Files.exists(p)) { + if (Files.isDirectory(p)) { + if (Files.newDirectoryStream(p).iterator().hasNext()) { + return; + } else { + throw new DirectoryNotEmptyException("Directory not empty."); + } + } + } else { + Files.createDirectory(p); + } + } catch (IOException e) { + throw e; + } + } + + @Override + public String[] getMountParameters() throws CommandFailedException { + ArrayList mountOptions = new ArrayList<>(8); + mountOptions.add(("-oatomic_o_trunc")); + try { + mountOptions.add("-ouid=" + getUIdOrGID("uid")); + mountOptions.add("-ogid=" + getUIdOrGID("gid")); + } catch (IOException e) { + e.printStackTrace(); + throw new CommandFailedException(e); + } + mountOptions.add("-oauto_unmount"); + mountOptions.add("-ofsname=CryptoFs"); + return mountOptions.toArray(new String [mountOptions.size()]); + } + + private String getUIdOrGID(String idtype) throws IOException { + String id; + String parameter; + switch (idtype) { + case "uid": + parameter = "-u"; + break; + case "gid": + parameter = "-g"; + break; + default: + throw new IllegalArgumentException("Unkown ID type"); + } + Process getId = new ProcessBuilder("sh", "-c", "id " + parameter).start(); + Scanner s = new Scanner(getId.getInputStream()).useDelimiter("\\A"); + try { + getId.waitFor(1000, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + id = s.nextLine(); + return id; + } + + @Override + public Path getFsRootPath() { + return this.root; + } + + @Override + public void revealFsRootInFilesystemManager() throws CommandFailedException { + throw new CommandFailedException("Not implemented."); + } + + @Override + public void cleanUp() { + try { + Files.deleteIfExists(Paths.get(vaultSettings.mountPath().get() + vaultSettings.mountName().get())); + } catch (IOException e) { + //LOG.warn("Could not delete mount directory of vault " + vaultSettings.mountName().get()); + e.printStackTrace(); + } + } + + @Override + public boolean supportsFuse() { + return true; + } +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/MacFuseEnvironment.java b/main/ui/src/main/java/org/cryptomator/ui/model/MacFuseEnvironment.java new file mode 100644 index 000000000..210e31f9d --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/model/MacFuseEnvironment.java @@ -0,0 +1,118 @@ +package org.cryptomator.ui.model; + +import org.cryptomator.common.settings.VaultSettings; + +import javax.inject.Inject; +import java.io.IOException; +import java.nio.file.DirectoryNotEmptyException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Scanner; +import java.util.concurrent.TimeUnit; + +public class MacFuseEnvironment implements FuseEnvironment { + + private final VaultSettings vaultSettings; + private Path root; + + @Inject + public MacFuseEnvironment(VaultSettings vaultSettings){ + this.vaultSettings = vaultSettings; + } + + @Override + public void prepare() throws CommandFailedException { + this.root = Paths.get(vaultSettings.mountPath().get() + vaultSettings.mountName().get()).toAbsolutePath(); + try { + createVaultDirIfNotExist(root); + } catch (IOException e) { + throw new CommandFailedException(e); + } + } + + private void createVaultDirIfNotExist(Path p) throws IOException { + try { + if (Files.exists(p)) { + if (Files.isDirectory(p)) { + if (Files.newDirectoryStream(p).iterator().hasNext()) { + return; + } else { + throw new DirectoryNotEmptyException("Directory not empty."); + } + } + } else { + Files.createDirectory(p); + } + } catch (IOException e) { + throw e; + } + } + + @Override + public String[] getMountParameters() throws CommandFailedException { + ArrayList mountOptions = new ArrayList<>(8); + mountOptions.add(("-oatomic_o_trunc")); + try { + mountOptions.add("-ouid=" + getUIdOrGID("uid")); + mountOptions.add("-ogid=" + getUIdOrGID("gid")); + } catch (IOException e) { + e.printStackTrace(); + throw new CommandFailedException(e); + } + mountOptions.add("-ovolname=" + vaultSettings.mountName().get()); + mountOptions.add("-oauto_xattr"); + return mountOptions.toArray(new String [mountOptions.size()]); + } + + private String getUIdOrGID(String idtype) throws IOException { + String id; + String parameter; + switch (idtype) { + case "uid": + parameter = "-u"; + break; + case "gid": + parameter = "-g"; + break; + default: + throw new IllegalArgumentException("Unkown ID type"); + } + Process getId = new ProcessBuilder("sh", "-c", "id " + parameter).start(); + Scanner s = new Scanner(getId.getInputStream()).useDelimiter("\\A"); + try { + getId.waitFor(1000, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + id = s.nextLine(); + return id; + } + + @Override + public Path getFsRootPath() { + return root; + } + + @Override + public void revealFsRootInFilesystemManager() throws CommandFailedException { + throw new CommandFailedException("Not implemented."); + } + + + @Override + public void cleanUp() { + try { + Files.deleteIfExists(Paths.get(vaultSettings.mountPath().get() + vaultSettings.mountName().get())); + } catch (IOException e) { + //LOG.warn("Could not delete mount directory of vault " + vaultSettings.mountName().get()); + e.printStackTrace(); + } + } + + @Override + public boolean supportsFuse() { + return false; + } +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/NioAdapter.java b/main/ui/src/main/java/org/cryptomator/ui/model/NioAdapter.java index e834993a2..df4238cc7 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/NioAdapter.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/NioAdapter.java @@ -20,7 +20,7 @@ public interface NioAdapter { void stop(); - String getFilesystemRootUrl(); + String getFsRootUrlString(); default boolean isSupported() { return false; diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java index 57a60e901..ec60abd11 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java @@ -299,7 +299,7 @@ public class Vault { } public String getFilesystemRootUrl() { - return nioAdapter.getFilesystemRootUrl(); + return nioAdapter.getFsRootUrlString(); } public String getId() { diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/VaultModule.java b/main/ui/src/main/java/org/cryptomator/ui/model/VaultModule.java index d456d4f1f..76783b5cb 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/VaultModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/VaultModule.java @@ -12,6 +12,7 @@ import java.util.Objects; import javax.inject.Scope; +import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.VaultSettings; @@ -55,4 +56,41 @@ public class VaultModule { throw new IllegalStateException("Unsupported NioAdapter: " + settings.usedNioAdapterImpl().get()); } } + + //TODO: ask sebi if this should be here + + private final OS os = OS.getCurrentOS(); + + private enum OS { + WINDOWS, + LINUX, + MAC; + + public static OS getCurrentOS() { + if (SystemUtils.IS_OS_WINDOWS) { + return WINDOWS; + } else if (SystemUtils.IS_OS_MAC) { + return MAC; + } else { + return LINUX; + } + } + + } + + @Provides + @VaultModule.PerVault + FuseEnvironment providesFuseEnvironment(WindowsFuseEnvironment windowsFuseEnvironment, LinuxFuseEnvironment linuxFuseEnvironment, MacFuseEnvironment macFuseEnvironment){ + switch (os){ + case LINUX: + return linuxFuseEnvironment; + case WINDOWS: + return windowsFuseEnvironment; + case MAC: + return macFuseEnvironment; + default: + //TODO: should be better something else returned? + return null; + } + } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/WebDavNioAdapter.java b/main/ui/src/main/java/org/cryptomator/ui/model/WebDavNioAdapter.java index d2813e22f..0f1e9b7cd 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/WebDavNioAdapter.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/WebDavNioAdapter.java @@ -104,7 +104,7 @@ public class WebDavNioAdapter implements NioAdapter { } - public synchronized String getFilesystemRootUrl() { + public synchronized String getFsRootUrlString() { return servlet.getServletRootUri().toString(); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/WindowsFuseEnvironment.java b/main/ui/src/main/java/org/cryptomator/ui/model/WindowsFuseEnvironment.java new file mode 100644 index 000000000..1111ead90 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/model/WindowsFuseEnvironment.java @@ -0,0 +1,69 @@ +package org.cryptomator.ui.model; + +import org.cryptomator.common.settings.VaultSettings; + +import javax.inject.Inject; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; + +@VaultModule.PerVault +public class WindowsFuseEnvironment implements FuseEnvironment{ + + private static final String AUTOASSIGN_DRRIVE_LETTER = "*"; + + private final VaultSettings vaultSettings; + private final WindowsDriveLetters windowsDriveLetters; + + private Path root; + + @Inject + public WindowsFuseEnvironment(VaultSettings vaultSettings, WindowsDriveLetters windowsDriveLetters){ + this.vaultSettings = vaultSettings; + this.windowsDriveLetters = windowsDriveLetters; + } + + @Override + public void prepare() throws CommandFailedException { + if (vaultSettings.winDriveLetter().get().equals(AUTOASSIGN_DRRIVE_LETTER)) { + if (!windowsDriveLetters.getAvailableDriveLetters().isEmpty()) { + root= Paths.get(windowsDriveLetters.getAvailableDriveLetters().iterator().next() + ":\\").toAbsolutePath(); + } else { + throw new CommandFailedException("No free drive letter to mount."); + } + } else { + root = Paths.get(vaultSettings.winDriveLetter().get() + ":\\").toAbsolutePath(); + } + } + + @Override + public String[] getMountParameters() throws CommandFailedException { + ArrayList mountOptions = new ArrayList<>(8); + mountOptions.add(("-oatomic_o_trunc")); + mountOptions.add("-ouid=-1"); + mountOptions.add("-ogid=-1"); + mountOptions.add("-ovolname=" + vaultSettings.mountName().get()); + mountOptions.add("-oFileInfoTimeout=-1"); + return mountOptions.toArray(new String [mountOptions.size()]); + } + + @Override + public Path getFsRootPath() { + return root; + } + + @Override + public void revealFsRootInFilesystemManager() throws CommandFailedException { + throw new CommandFailedException("Not Implemented"); + } + + @Override + public void cleanUp() { + + } + + @Override + public boolean supportsFuse() { + return false; + } +}