소스 검색

Added implementations for MountPointChooser

Added AvailableDriveLetterChooser for automatic DriveLetter-choice
Added CustomDriveLetterChooser for a chosen DriveLetter
Added CustomMountPointChooser for a chosen directory
Added TemporaryMountPointChooser for automatic directory-choice
JaniruTEC 5 년 전
부모
커밋
d6bbc4383b

+ 26 - 0
main/commons/src/main/java/org/cryptomator/common/mountpoint/AvailableDriveLetterChooser.java

@@ -0,0 +1,26 @@
+package org.cryptomator.common.mountpoint;
+
+import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.common.vaults.WindowsDriveLetters;
+
+import java.nio.file.Path;
+import java.util.Optional;
+
+public class AvailableDriveLetterChooser implements MountPointChooser {
+
+	private final WindowsDriveLetters windowsDriveLetters;
+
+	public AvailableDriveLetterChooser(WindowsDriveLetters windowsDriveLetters) {
+		this.windowsDriveLetters = windowsDriveLetters;
+	}
+
+	@Override
+	public boolean isApplicable() {
+		return SystemUtils.IS_OS_WINDOWS;
+	}
+
+	@Override
+	public Optional<Path> chooseMountPoint() {
+		return this.windowsDriveLetters.getAvailableDriveLetterPath();
+	}
+}

+ 28 - 0
main/commons/src/main/java/org/cryptomator/common/mountpoint/CustomDriveLetterChooser.java

@@ -0,0 +1,28 @@
+package org.cryptomator.common.mountpoint;
+
+import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.common.settings.VaultSettings;
+import org.cryptomator.common.vaults.Vault;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+
+public class CustomDriveLetterChooser implements MountPointChooser {
+
+	private final VaultSettings vaultSettings;
+
+	public CustomDriveLetterChooser(Vault vault) {
+		this.vaultSettings = vault.getVaultSettings();
+	}
+
+	@Override
+	public boolean isApplicable() {
+		return SystemUtils.IS_OS_WINDOWS;
+	}
+
+	@Override
+	public Optional<Path> chooseMountPoint() {
+		return this.vaultSettings.getWinDriveLetter().map(letter -> letter.charAt(0) + ":\\").map(Paths::get);
+	}
+}

+ 69 - 0
main/commons/src/main/java/org/cryptomator/common/mountpoint/CustomMountPointChooser.java

@@ -0,0 +1,69 @@
+package org.cryptomator.common.mountpoint;
+
+import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.common.settings.VaultSettings;
+import org.cryptomator.common.vaults.Vault;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.file.DirectoryNotEmptyException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.NotDirectoryException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+
+public class CustomMountPointChooser implements MountPointChooser {
+
+	private static final Logger LOG = LoggerFactory.getLogger(CustomMountPointChooser.class);
+
+	private final VaultSettings vaultSettings;
+
+	public CustomMountPointChooser(Vault vault) {
+		this.vaultSettings = vault.getVaultSettings();
+	}
+
+	@Override
+	public Optional<Path> chooseMountPoint() {
+		//VaultSettings#getCustomMountPath already checks whether the saved custom mountpoint should be used
+		return this.vaultSettings.getCustomMountPath().map(Paths::get);
+	}
+
+	@Override
+	public boolean prepare(Path mountPoint) throws InvalidMountPointException {
+		//On Windows the target folder MUST NOT exist...
+		//https://github.com/billziss-gh/winfsp/issues/320
+		if (SystemUtils.IS_OS_WINDOWS) {
+			//We must use #notExists() here because notExists =/= !exists (see docs)
+			if (Files.notExists(mountPoint, LinkOption.NOFOLLOW_LINKS)) {
+				//File really doesn't exist
+				return false;
+			}
+			//File exists OR can't be determined
+			throw wrapAsIMPE(new FileAlreadyExistsException(mountPoint.toString()));
+		}
+
+		//... on Mac and Linux it's the opposite
+		if (!Files.isDirectory(mountPoint)) {
+			throw wrapAsIMPE(new NotDirectoryException(mountPoint.toString()));
+		}
+		try (DirectoryStream<Path> ds = Files.newDirectoryStream(mountPoint)) {
+			if (ds.iterator().hasNext()) {
+				throw wrapAsIMPE(new DirectoryNotEmptyException(mountPoint.toString()));
+			}
+		} catch (IOException exception) {
+			throw wrapAsIMPE(exception);
+		}
+		LOG.debug("Successfully checked custom mount point: {}", mountPoint);
+		return false;
+	}
+
+	private InvalidMountPointException wrapAsIMPE(Exception exception) {
+		return new InvalidMountPointException(exception);
+	}
+
+}

+ 79 - 0
main/commons/src/main/java/org/cryptomator/common/mountpoint/TemporaryMountPointChooser.java

@@ -0,0 +1,79 @@
+package org.cryptomator.common.mountpoint;
+
+import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.common.Environment;
+import org.cryptomator.common.settings.VaultSettings;
+import org.cryptomator.common.vaults.Vault;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+
+public class TemporaryMountPointChooser implements MountPointChooser {
+
+	private static final Logger LOG = LoggerFactory.getLogger(TemporaryMountPointChooser.class);
+	private static final int MAX_TMPMOUNTPOINT_CREATION_RETRIES = 10;
+
+	private final VaultSettings vaultSettings;
+	private final Environment environment;
+
+	public TemporaryMountPointChooser(Vault vault, Environment environment) {
+		this.vaultSettings = vault.getVaultSettings();
+		this.environment = environment;
+	}
+
+	@Override
+	public boolean isApplicable() {
+		if(this.environment.getMountPointsDir().isEmpty()) {
+			LOG.warn("\"cryptomator.mountPointsDir\" is not set to a valid path!");
+			return false;
+		}
+		return true;
+	}
+
+	@Override
+	public Optional<Path> chooseMountPoint() {
+		//Shouldn't throw, but let's keep #orElseThrow in case we made a mistake and the check in #isApplicable failed
+		Path parent = this.environment.getMountPointsDir().orElseThrow();
+		String basename = this.vaultSettings.getId();
+		for (int i = 0; i < MAX_TMPMOUNTPOINT_CREATION_RETRIES; i++) {
+			Path mountPoint = parent.resolve(basename + "_" + i);
+			if (Files.notExists(mountPoint)) {
+				return Optional.of(mountPoint);
+			}
+		}
+		return Optional.empty();
+	}
+
+	@Override
+	public boolean prepare(Path mountPoint) throws InvalidMountPointException {
+		// https://github.com/osxfuse/osxfuse/issues/306#issuecomment-245114592:
+		// In order to allow non-admin users to mount FUSE volumes in `/Volumes`,
+		// starting with version 3.5.0, FUSE will create non-existent mount points automatically.
+		if (SystemUtils.IS_OS_MAC && mountPoint.getParent().equals(Paths.get("/Volumes"))) {
+			return false;
+		}
+
+		try {
+			//WinFSP needs the parent, but the actual Mountpoint must not exist...
+			if (SystemUtils.IS_OS_WINDOWS) {
+				Files.createDirectories(mountPoint.getParent());
+				return false;
+			} else {
+				//For Linux and Mac the actual Mountpoint must exist
+				Files.createDirectories(mountPoint);
+				return true;
+			}
+		} catch (IOException exception) {
+			throw wrapAsIMPE(exception);
+		}
+	}
+
+	private InvalidMountPointException wrapAsIMPE(Exception exception) {
+		return new InvalidMountPointException(exception);
+	}
+}