introduce new FuseEnvironment Interface such that the fuseNioAdapter gets os-dependent information from it

This commit is contained in:
infeo
2018-02-05 21:20:29 +01:00
parent bf637f8361
commit b069a16f0c
9 changed files with 393 additions and 158 deletions

View File

@@ -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;
}
}

View File

@@ -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<String> 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

View File

@@ -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<String> 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;
}
}

View File

@@ -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<String> 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;
}
}

View File

@@ -20,7 +20,7 @@ public interface NioAdapter {
void stop();
String getFilesystemRootUrl();
String getFsRootUrlString();
default boolean isSupported() {
return false;

View File

@@ -299,7 +299,7 @@ public class Vault {
}
public String getFilesystemRootUrl() {
return nioAdapter.getFilesystemRootUrl();
return nioAdapter.getFsRootUrlString();
}
public String getId() {

View File

@@ -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;
}
}
}

View File

@@ -104,7 +104,7 @@ public class WebDavNioAdapter implements NioAdapter {
}
public synchronized String getFilesystemRootUrl() {
public synchronized String getFsRootUrlString() {
return servlet.getServletRootUri().toString();
}

View File

@@ -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<String> 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;
}
}