mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-20 19:51:27 +00:00
integration of the fuseNioAdapter, including all the gui (controller & fxml) and settings wiring. english localization fitted and enriched for fuse
This commit is contained in:
@@ -30,6 +30,8 @@ public class Settings {
|
||||
public static final int DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
|
||||
public static final String DEFAULT_GVFS_SCHEME = "dav";
|
||||
public static final boolean DEFAULT_DEBUG_MODE = false;
|
||||
public static final String DEFAULT_DEFAULT_MOUNT_DIR = System.getProperty("user.home");
|
||||
public static final String DEFAULT_NIO_ADAPTER = "WEBDAV";
|
||||
|
||||
private final ObservableList<VaultSettings> directories = FXCollections.observableArrayList(VaultSettings::observables);
|
||||
private final BooleanProperty checkForUpdates = new SimpleBooleanProperty(DEFAULT_CHECK_FOR_UDPATES);
|
||||
@@ -37,6 +39,9 @@ public class Settings {
|
||||
private final IntegerProperty numTrayNotifications = new SimpleIntegerProperty(DEFAULT_NUM_TRAY_NOTIFICATIONS);
|
||||
private final StringProperty preferredGvfsScheme = new SimpleStringProperty(DEFAULT_GVFS_SCHEME);
|
||||
private final BooleanProperty debugMode = new SimpleBooleanProperty(DEFAULT_DEBUG_MODE);
|
||||
private final StringProperty nioAdapterImpl = new SimpleStringProperty(DEFAULT_NIO_ADAPTER);
|
||||
private final StringProperty defaultMountDir = new SimpleStringProperty(DEFAULT_DEFAULT_MOUNT_DIR);
|
||||
|
||||
private Consumer<Settings> saveCmd;
|
||||
|
||||
/**
|
||||
@@ -49,6 +54,8 @@ public class Settings {
|
||||
numTrayNotifications.addListener(this::somethingChanged);
|
||||
preferredGvfsScheme.addListener(this::somethingChanged);
|
||||
debugMode.addListener(this::somethingChanged);
|
||||
nioAdapterImpl.addListener(this::somethingChanged);
|
||||
defaultMountDir.addListener(this::somethingChanged);
|
||||
}
|
||||
|
||||
void setSaveCmd(Consumer<Settings> saveCmd) {
|
||||
@@ -91,4 +98,11 @@ public class Settings {
|
||||
return debugMode;
|
||||
}
|
||||
|
||||
public StringProperty usedNioAdapterImpl() {
|
||||
return nioAdapterImpl;
|
||||
}
|
||||
|
||||
public StringProperty defaultMountDir() {
|
||||
return defaultMountDir;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
|
||||
out.name("numTrayNotifications").value(value.numTrayNotifications().get());
|
||||
out.name("preferredGvfsScheme").value(value.preferredGvfsScheme().get());
|
||||
out.name("debugMode").value(value.debugMode().get());
|
||||
out.name("nioAdapterImpl").value(value.usedNioAdapterImpl().get());
|
||||
out.name("defaultMountDir").value(value.defaultMountDir().get());
|
||||
out.endObject();
|
||||
}
|
||||
|
||||
@@ -70,6 +72,12 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
|
||||
case "debugMode":
|
||||
settings.debugMode().set(in.nextBoolean());
|
||||
break;
|
||||
case "nioAdapterImpl":
|
||||
settings.usedNioAdapterImpl().set(in.nextString());
|
||||
break;
|
||||
case "defaultMountDir":
|
||||
settings.defaultMountDir().set(in.nextString());
|
||||
break;
|
||||
default:
|
||||
LOG.warn("Unsupported vault setting found in JSON: " + name);
|
||||
in.skipValue();
|
||||
|
||||
@@ -36,6 +36,7 @@ public class VaultSettings {
|
||||
private final BooleanProperty unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP);
|
||||
private final BooleanProperty mountAfterUnlock = new SimpleBooleanProperty(DEFAULT_MOUNT_AFTER_UNLOCK);
|
||||
private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REAVEAL_AFTER_MOUNT);
|
||||
private final StringProperty mountPath = new SimpleStringProperty(Settings.DEFAULT_DEFAULT_MOUNT_DIR);
|
||||
|
||||
public VaultSettings(String id) {
|
||||
this.id = Objects.requireNonNull(id);
|
||||
@@ -123,6 +124,10 @@ public class VaultSettings {
|
||||
return revealAfterMount;
|
||||
}
|
||||
|
||||
public StringProperty mountPath() {
|
||||
return mountPath;
|
||||
}
|
||||
|
||||
/* Hashcode/Equals */
|
||||
|
||||
@Override
|
||||
|
||||
@@ -34,6 +34,7 @@ class VaultSettingsJsonAdapter {
|
||||
String id = null;
|
||||
String path = null;
|
||||
String mountName = null;
|
||||
String mountPath = null;
|
||||
String winDriveLetter = null;
|
||||
boolean unlockAfterStartup = VaultSettings.DEFAULT_UNLOCK_AFTER_STARTUP;
|
||||
boolean mountAfterUnlock = VaultSettings.DEFAULT_MOUNT_AFTER_UNLOCK;
|
||||
@@ -64,6 +65,8 @@ class VaultSettingsJsonAdapter {
|
||||
case "revealAfterMount":
|
||||
revealAfterMount = in.nextBoolean();
|
||||
break;
|
||||
case "mountPath":
|
||||
mountPath = in.nextString();
|
||||
default:
|
||||
LOG.warn("Unsupported vault setting found in JSON: " + name);
|
||||
in.skipValue();
|
||||
@@ -78,6 +81,7 @@ class VaultSettingsJsonAdapter {
|
||||
vaultSettings.unlockAfterStartup().set(unlockAfterStartup);
|
||||
vaultSettings.mountAfterUnlock().set(mountAfterUnlock);
|
||||
vaultSettings.revealAfterMount().set(revealAfterMount);
|
||||
vaultSettings.mountPath().set(mountPath);
|
||||
return vaultSettings;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
<cryptomator.cryptofs.version>1.4.5</cryptomator.cryptofs.version>
|
||||
<cryptomator.webdav.version>1.0.3</cryptomator.webdav.version>
|
||||
<cryptomator.jni.version>1.0.2</cryptomator.jni.version>
|
||||
|
||||
<cryptomator.fuse.version>0.1.1-SNAPSHOT</cryptomator.fuse.version>
|
||||
|
||||
<commons-io.version>2.5</commons-io.version>
|
||||
<commons-lang3.version>3.6</commons-lang3.version>
|
||||
<httpclient.version>4.5.3</httpclient.version>
|
||||
@@ -96,6 +97,11 @@
|
||||
<artifactId>cryptofs</artifactId>
|
||||
<version>${cryptomator.cryptofs.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>fuse-nio-adapter</artifactId>
|
||||
<version>${cryptomator.fuse.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>webdav-nio-adapter</artifactId>
|
||||
|
||||
@@ -30,7 +30,11 @@
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>keychain</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>fuse-nio-adapter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- CryptoLib -->
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
|
||||
@@ -8,15 +8,22 @@
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.controllers;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.ui.l10n.Localization;
|
||||
import org.cryptomator.ui.model.NioAdapterImpl;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.Strings;
|
||||
@@ -52,6 +59,15 @@ public class SettingsController implements ViewController {
|
||||
@FXML
|
||||
private CheckBox checkForUpdatesCheckbox;
|
||||
|
||||
@FXML
|
||||
private GridPane webdavNioAdapter;
|
||||
|
||||
@FXML
|
||||
private GridPane fuseNioAdapter;
|
||||
|
||||
@FXML
|
||||
private Label portFieldLabel;
|
||||
|
||||
@FXML
|
||||
private TextField portField;
|
||||
|
||||
@@ -64,9 +80,24 @@ public class SettingsController implements ViewController {
|
||||
@FXML
|
||||
private Label prefGvfsSchemeLabel;
|
||||
|
||||
@FXML
|
||||
private Label defaultMountDirLabel;
|
||||
|
||||
@FXML
|
||||
private TextField defaultMountDir;
|
||||
|
||||
@FXML
|
||||
private Button changeDefaultMountDirButton;
|
||||
|
||||
@FXML
|
||||
private ChoiceBox<String> prefGvfsScheme;
|
||||
|
||||
@FXML
|
||||
private Label nioAdapterLabel;
|
||||
|
||||
@FXML
|
||||
private ChoiceBox<String> nioAdapter;
|
||||
|
||||
@FXML
|
||||
private CheckBox debugModeCheckbox;
|
||||
|
||||
@@ -75,25 +106,69 @@ public class SettingsController implements ViewController {
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
versionLabel.setText(String.format(localization.getString("settings.version.label"), applicationVersion.orElse("SNAPSHOT")));
|
||||
checkForUpdatesCheckbox.setDisable(areUpdatesManagedExternally());
|
||||
checkForUpdatesCheckbox.setSelected(settings.checkForUpdates().get() && !areUpdatesManagedExternally());
|
||||
|
||||
//NIOADAPTER
|
||||
nioAdapter.getItems().addAll(getSupportedAdapters());
|
||||
nioAdapter.setValue(settings.usedNioAdapterImpl().get());
|
||||
nioAdapter.setVisible(true);
|
||||
nioAdapter.getSelectionModel().selectedItemProperty().addListener( (ObservableValue<? extends String> observable, String oldVal, String newVal) -> changeNioView(newVal) );
|
||||
|
||||
|
||||
//WEBDAV
|
||||
webdavNioAdapter.managedProperty().bind(webdavNioAdapter.visibleProperty());
|
||||
prefGvfsScheme.managedProperty().bind(webdavNioAdapter.visibleProperty());
|
||||
prefGvfsSchemeLabel.managedProperty().bind(webdavNioAdapter.visibleProperty());
|
||||
portFieldLabel.managedProperty().bind(webdavNioAdapter.visibleProperty());
|
||||
changePortButton.managedProperty().bind(webdavNioAdapter.visibleProperty());
|
||||
portField.managedProperty().bind(webdavNioAdapter.visibleProperty());
|
||||
portField.setText(String.valueOf(settings.port().intValue()));
|
||||
portField.addEventFilter(KeyEvent.KEY_TYPED, this::filterNumericKeyEvents);
|
||||
changePortButton.visibleProperty().bind(settings.port().asString().isNotEqualTo(portField.textProperty()));
|
||||
changePortButton.disableProperty().bind(Bindings.createBooleanBinding(this::isPortValid, portField.textProperty()).not());
|
||||
versionLabel.setText(String.format(localization.getString("settings.version.label"), applicationVersion.orElse("SNAPSHOT")));
|
||||
prefGvfsSchemeLabel.setVisible(SystemUtils.IS_OS_LINUX);
|
||||
prefGvfsScheme.setVisible(SystemUtils.IS_OS_LINUX);
|
||||
prefGvfsScheme.getItems().add("dav");
|
||||
prefGvfsScheme.getItems().add("webdav");
|
||||
prefGvfsScheme.setValue(settings.preferredGvfsScheme().get());
|
||||
prefGvfsSchemeLabel.setVisible(SystemUtils.IS_OS_LINUX);
|
||||
prefGvfsScheme.setVisible(SystemUtils.IS_OS_LINUX);
|
||||
|
||||
//FUSE
|
||||
fuseNioAdapter.managedProperty().bind(fuseNioAdapter.visibleProperty());
|
||||
defaultMountDirLabel.managedProperty().bind(fuseNioAdapter.visibleProperty());
|
||||
defaultMountDir.managedProperty().bind(fuseNioAdapter.visibleProperty());
|
||||
defaultMountDirLabel.setVisible(SystemUtils.IS_OS_LINUX);
|
||||
defaultMountDir.setVisible(SystemUtils.IS_OS_LINUX);
|
||||
defaultMountDir.setText(String.valueOf(settings.defaultMountDir().get()));
|
||||
changeDefaultMountDirButton.setVisible(false);
|
||||
changeDefaultMountDirButton.visibleProperty().bind(
|
||||
Bindings.createBooleanBinding(
|
||||
() -> fuseNioAdapter.visibleProperty().get() && settings.defaultMountDir().isNotEqualTo(Strings.nullToEmpty(defaultMountDir.getText())).get() ,
|
||||
fuseNioAdapter.visibleProperty(),
|
||||
settings.defaultMountDir().isNotEqualTo(defaultMountDir.textProperty())
|
||||
)
|
||||
);
|
||||
changeDefaultMountDirButton.disableProperty().bind(Bindings.createBooleanBinding(this::isDirValid, defaultMountDir.textProperty()).not());
|
||||
|
||||
debugModeCheckbox.setSelected(settings.debugMode().get());
|
||||
|
||||
settings.checkForUpdates().bind(checkForUpdatesCheckbox.selectedProperty());
|
||||
settings.preferredGvfsScheme().bind(prefGvfsScheme.valueProperty());
|
||||
settings.usedNioAdapterImpl().bind(nioAdapter.valueProperty());
|
||||
settings.debugMode().bind(debugModeCheckbox.selectedProperty());
|
||||
}
|
||||
|
||||
//TODO: how to implement this?
|
||||
private String [] getSupportedAdapters() {
|
||||
return new String[]{NioAdapterImpl.FUSE.name(), NioAdapterImpl.WEBDAV.name()};
|
||||
}
|
||||
|
||||
private void changeNioView(String newVal) {
|
||||
fuseNioAdapter.setVisible(newVal.equalsIgnoreCase("FUSE"));
|
||||
webdavNioAdapter.setVisible(newVal.equalsIgnoreCase("WEBDAV"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parent getRoot() {
|
||||
return root;
|
||||
@@ -110,6 +185,23 @@ public class SettingsController implements ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void changeDefaultMountDir(ActionEvent event){
|
||||
assert isDirValid() : "Error. Not a valid Directory. Does and exist and do you have the needed Rights?";
|
||||
settings.defaultMountDir().set(defaultMountDir.getText());
|
||||
}
|
||||
|
||||
private boolean isDirValid(){
|
||||
if(SystemUtils.IS_OS_WINDOWS){
|
||||
//this should never ever happen!
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
Path path = Paths.get(defaultMountDir.getText());
|
||||
return Files.isDirectory(path) && Files.isReadable(path) && Files.isWritable(path) && Files.isExecutable(path);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPortValid() {
|
||||
try {
|
||||
int port = Integer.parseInt(portField.getText());
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.controllers;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
@@ -16,6 +18,8 @@ import java.util.Optional;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import org.apache.commons.lang3.CharUtils;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.settings.VaultSettings;
|
||||
@@ -112,6 +116,15 @@ public class UnlockController implements ViewController {
|
||||
@FXML
|
||||
private ChoiceBox<Character> winDriveLetter;
|
||||
|
||||
@FXML
|
||||
private Label mountPathLabel;
|
||||
|
||||
@FXML
|
||||
private TextField mountPath;
|
||||
|
||||
@FXML
|
||||
private Button changeMountPathButton;
|
||||
|
||||
@FXML
|
||||
private ProgressIndicator progressIndicator;
|
||||
|
||||
@@ -142,12 +155,26 @@ public class UnlockController implements ViewController {
|
||||
unlockAfterStartup.disableProperty().bind(savePassword.disabledProperty().or(savePassword.selectedProperty().not()));
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
winDriveLetter.setConverter(new WinDriveLetterLabelConverter());
|
||||
mountPathLabel.setVisible(false);
|
||||
mountPathLabel.setManaged(false);
|
||||
mountPath.setVisible(false);
|
||||
mountPath.setManaged(false);
|
||||
changeMountPathButton.setVisible(false);
|
||||
changeMountPathButton.setManaged(false);
|
||||
} else {
|
||||
winDriveLetterLabel.setVisible(false);
|
||||
winDriveLetterLabel.setManaged(false);
|
||||
winDriveLetter.setVisible(false);
|
||||
winDriveLetter.setManaged(false);
|
||||
}
|
||||
changeMountPathButton.disableProperty().bind(Bindings.createBooleanBinding(this::isDirVaild, mountPath.textProperty()).not());
|
||||
changeMountPathButton.visibleProperty().bind(
|
||||
Bindings.createBooleanBinding(
|
||||
()-> mountPathLabel.isVisible() && mountPath.textProperty().isEmpty().not().get(),
|
||||
mountPathLabel.visibleProperty(),
|
||||
mountPath.textProperty().isEmpty().not()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -208,6 +235,7 @@ public class UnlockController implements ViewController {
|
||||
vaultSubs = vaultSubs.and(EasyBind.subscribe(unlockAfterStartup.selectedProperty(), settings.unlockAfterStartup()::set));
|
||||
vaultSubs = vaultSubs.and(EasyBind.subscribe(mountAfterUnlock.selectedProperty(), settings.mountAfterUnlock()::set));
|
||||
vaultSubs = vaultSubs.and(EasyBind.subscribe(revealAfterMount.selectedProperty(), settings.revealAfterMount()::set));
|
||||
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
@@ -233,6 +261,32 @@ public class UnlockController implements ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void didClickchangeMountPathButton(ActionEvent event){
|
||||
assert isDirVaild();
|
||||
vault.setMountPath(mountPath.getText());
|
||||
}
|
||||
|
||||
private boolean isDirVaild(){
|
||||
try{
|
||||
if(!mountPath.textProperty().isEmpty().get()){
|
||||
Path p = Paths.get(mountPath.textProperty().get());
|
||||
return Files.isDirectory(p) && Files.isReadable(p) && Files.isWritable(p) && Files.isExecutable(p);
|
||||
}
|
||||
else{
|
||||
//default path will be taken
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
catch (InvalidPathException e){
|
||||
LOG.info("Invalid path");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void filterAlphanumericKeyEvents(KeyEvent t) {
|
||||
if (!Strings.isNullOrEmpty(t.getCharacter()) && !ALPHA_NUMERIC_MATCHER.matchesAllOf(t.getCharacter())) {
|
||||
t.consume();
|
||||
|
||||
@@ -18,7 +18,6 @@ import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.cryptomator.cryptolib.api.CryptoException;
|
||||
import org.cryptomator.frontend.webdav.mount.Mounter.CommandFailedException;
|
||||
import org.cryptomator.keychain.KeychainAccess;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
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 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock(CryptoFileSystem fs) {
|
||||
this.cfs = fs;
|
||||
ffs = AdapterFactory.createReadWriteAdapter(fs.getPath("/"));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: should createTempDirectory() be used instead of createDirectory()?
|
||||
*
|
||||
* @throws CommandFailedException
|
||||
*/
|
||||
@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) {
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unmount() throws CommandFailedException {
|
||||
if (!(cfs.getStats().pollBytesRead() > 0 || cfs.getStats().pollBytesWritten() > 0)) {
|
||||
unmountForced();
|
||||
} else {
|
||||
throw new CommandFailedException("Pending read or write operations.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unmountForced() throws CommandFailedException {
|
||||
ffs.umount();
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilesystemRootUrl() {
|
||||
return mountURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsForcedUnmount() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,13 +43,13 @@ public class VaultModule {
|
||||
|
||||
@Provides
|
||||
@PerVault
|
||||
public NioAdapter provideNioAdpater(Settings settings, WebDavNioAdapter webDavNioAdapter) {
|
||||
public NioAdapter provideNioAdpater(Settings settings, WebDavNioAdapter webDavNioAdapter, FuseNioAdapter fuseNioAdapter) {
|
||||
NioAdapterImpl impl = NioAdapterImpl.valueOf(settings.usedNioAdapterImpl().get());
|
||||
switch (impl) {
|
||||
case WEBDAV:
|
||||
return webDavNioAdapter;
|
||||
case FUSE:
|
||||
throw new NotImplementedException();
|
||||
return fuseNioAdapter;
|
||||
default:
|
||||
//this should not happen!
|
||||
throw new IllegalStateException("Unsupported NioAdapter: " + settings.usedNioAdapterImpl().get());
|
||||
|
||||
@@ -35,22 +35,37 @@
|
||||
<!-- Row 0 -->
|
||||
<Label GridPane.rowIndex="0" GridPane.columnIndex="0" text="%settings.checkForUpdates.label" cacheShape="true" cache="true" />
|
||||
<CheckBox GridPane.rowIndex="0" GridPane.columnIndex="1" fx:id="checkForUpdatesCheckbox" cacheShape="true" cache="true" />
|
||||
|
||||
|
||||
<!-- Row 1 -->
|
||||
<Label GridPane.rowIndex="1" GridPane.columnIndex="0" text="%settings.port.label" cacheShape="true" cache="true" />
|
||||
<HBox GridPane.rowIndex="1" GridPane.columnIndex="1" spacing="6.0">
|
||||
<TextField fx:id="portField" cacheShape="true" cache="true" promptText="%settings.port.prompt" />
|
||||
<Button text="%settings.port.apply" fx:id="changePortButton" onAction="#changePort"/>
|
||||
</HBox>
|
||||
|
||||
<Label GridPane.rowIndex="1" GridPane.columnIndex="0" text="%settings.debugMode.label" cacheShape="true" cache="true" />
|
||||
<CheckBox GridPane.rowIndex="1" GridPane.columnIndex="1" fx:id="debugModeCheckbox" cacheShape="true" cache="true" />
|
||||
|
||||
<!-- Row 2 -->
|
||||
<Label GridPane.rowIndex="2" GridPane.columnIndex="0" fx:id="prefGvfsSchemeLabel" text="%settings.prefGvfsScheme.label" cacheShape="true" cache="true" />
|
||||
<ChoiceBox GridPane.rowIndex="2" GridPane.columnIndex="1" fx:id="prefGvfsScheme" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
|
||||
|
||||
<!-- Row 3 -->
|
||||
<Label GridPane.rowIndex="3" GridPane.columnIndex="0" text="%settings.debugMode.label" cacheShape="true" cache="true" />
|
||||
<CheckBox GridPane.rowIndex="3" GridPane.columnIndex="1" fx:id="debugModeCheckbox" cacheShape="true" cache="true" />
|
||||
|
||||
<Label fx:id="nioAdapterLabel" GridPane.rowIndex="2" GridPane.columnIndex="0" text="%settings.nioAdapter.label" cacheShape="true" cache="true" />
|
||||
<ChoiceBox GridPane.rowIndex="2" GridPane.columnIndex="1" fx:id="nioAdapter" cacheShape="true" cache="true" />
|
||||
|
||||
<!-- Row 3 Alt 1-->
|
||||
<GridPane fx:id="webdavNioAdapter" vgap="12.0" hgap="12.0" GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2" visible="true" cacheShape="true" cache="true">
|
||||
<Label fx:id="portFieldLabel" GridPane.rowIndex="3" GridPane.columnIndex="0" text="%settings.webdav.port.label" cacheShape="true" cache="true" />
|
||||
<HBox GridPane.rowIndex="3" GridPane.columnIndex="1" spacing="6.0">
|
||||
<TextField fx:id="portField" cacheShape="true" cache="true" promptText="%settings.webdav.port.prompt" />
|
||||
<Button text="%settings.webdav.port.apply" fx:id="changePortButton" onAction="#changePort"/>
|
||||
</HBox>
|
||||
|
||||
<!-- Row 4 -->
|
||||
<Label GridPane.rowIndex="4" GridPane.columnIndex="0" fx:id="prefGvfsSchemeLabel" text="%settings.webdav.prefGvfsScheme.label" cacheShape="true" cache="true" />
|
||||
<ChoiceBox GridPane.rowIndex="4" GridPane.columnIndex="1" fx:id="prefGvfsScheme" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
|
||||
</GridPane>
|
||||
|
||||
<!-- Row 3 Alt 2-->
|
||||
<GridPane fx:id="fuseNioAdapter" vgap="12.0" hgap="12.0" GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2" visible="false" cacheShape="true" cache="true">
|
||||
<Label fx:id="defaultMountDirLabel" GridPane.rowIndex="3" GridPane.columnIndex="0" text="%settings.fuse.defaultMntDir.label" cacheShape="true" cache="true"/>
|
||||
<HBox GridPane.rowIndex="3" GridPane.columnIndex="1" spacing="6.0">
|
||||
<TextField fx:id="defaultMountDir" cacheShape="true" cache="true" promptText="%settings.fuse.defaultMntDir.defaultVal" />
|
||||
<Button text="%settings.webdav.port.apply" fx:id="changeDefaultMountDirButton" onAction="#changeDefaultMountDir"/>
|
||||
</HBox>
|
||||
</GridPane>
|
||||
|
||||
</children>
|
||||
</GridPane>
|
||||
<Label VBox.vgrow="NEVER" text="%settings.requiresRestartLabel" alignment="CENTER" cacheShape="true" cache="true" />
|
||||
|
||||
@@ -83,9 +83,17 @@
|
||||
<!-- Row 3.5 -->
|
||||
<CheckBox GridPane.rowIndex="5" GridPane.columnIndex="0" GridPane.columnSpan="2" fx:id="revealAfterMount" text="%unlock.label.revealAfterMount" cacheShape="true" cache="true" />
|
||||
|
||||
<!-- Row 3.6 -->
|
||||
<!-- Row 3.6 Alt1 -->
|
||||
<Label GridPane.rowIndex="6" GridPane.columnIndex="0" fx:id="winDriveLetterLabel" text="%unlock.label.winDriveLetter" cacheShape="true" cache="true" />
|
||||
<ChoiceBox GridPane.rowIndex="6" GridPane.columnIndex="1" fx:id="winDriveLetter" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
|
||||
|
||||
<!-- Row 3.6 Alt2 -->
|
||||
<Label GridPane.rowIndex="6" GridPane.columnIndex="0" fx:id="mountPathLabel" text="%unlock.label.mountPath" cacheShape="true" cache="true" />
|
||||
|
||||
<HBox GridPane.rowIndex="6" GridPane.columnIndex="1" spacing="6.0">
|
||||
<TextField GridPane.rowIndex="6" GridPane.columnIndex="1" fx:id="mountPath" cacheShape="true" cache="true" />
|
||||
<Button text="%unlock.label.mountPathButton" fx:id="changeMountPathButton" onAction="#didClickchangeMountPathButton"/>
|
||||
</HBox>
|
||||
</GridPane>
|
||||
|
||||
<!-- Row 4 -->
|
||||
|
||||
@@ -67,6 +67,8 @@ unlock.label.mountName=Drive Name
|
||||
unlock.label.unlockAfterStartup=Auto-Unlock on Start (Experimental)
|
||||
unlock.label.revealAfterMount=Reveal Drive
|
||||
unlock.label.winDriveLetter=Drive Letter
|
||||
unlock.label.mountPath=Mount Path
|
||||
unlock.label.mountPathButton=Apply
|
||||
unlock.label.downloadsPageLink=All Cryptomator versions
|
||||
unlock.label.advancedHeading=Advanced Options
|
||||
unlock.button.unlock=Unlock Vault
|
||||
@@ -97,7 +99,7 @@ unlocked.button.lock=Lock Vault
|
||||
unlocked.moreOptions.mount=Mount Drive
|
||||
unlocked.moreOptions.unmount=Eject Drive
|
||||
unlocked.moreOptions.reveal=Reveal Drive
|
||||
unlocked.moreOptions.copyUrl=Copy WebDAV URL
|
||||
unlocked.moreOptions.copyUrl=Copy Filesystem URL
|
||||
unlocked.label.mountFailed=Connecting drive failed
|
||||
unlocked.label.revealFailed=Command failed
|
||||
unlocked.label.unmountFailed=Ejecting drive failed
|
||||
@@ -111,12 +113,17 @@ unlocked.lock.force.confirmation.content=This may be because other programs are
|
||||
# settings.fxml
|
||||
settings.version.label=Version %s
|
||||
settings.checkForUpdates.label=Check for Updates
|
||||
settings.port.label=WebDAV Port
|
||||
settings.port.prompt=0 = Choose automatically
|
||||
settings.port.apply=Apply
|
||||
settings.prefGvfsScheme.label=WebDAV Scheme
|
||||
settings.webdav.port.label=WebDAV Port
|
||||
settings.webdav.port.prompt=0 = Choose automatically
|
||||
settings.webdav.port.apply=Apply
|
||||
settings.webdav.prefGvfsScheme.label=WebDAV Scheme
|
||||
settings.debugMode.label=Debug Mode *
|
||||
settings.requiresRestartLabel=* Cryptomator needs to restart
|
||||
settings.nioAdapter.label= Mount-Methode *
|
||||
settings.nioAdapter.webdav=WebDAV
|
||||
settings.nioAdapter.fuse=FUSE
|
||||
settings.fuse.defaultMntDir.label=Default mounting point
|
||||
settings.fuse.defaultMntDir.defaultVal=/dev/null
|
||||
|
||||
# tray icon
|
||||
tray.menu.open=Open
|
||||
|
||||
Reference in New Issue
Block a user