|
@@ -1,14 +1,5 @@
|
|
|
package org.cryptomator.ui.model;
|
|
|
|
|
|
-import java.io.IOException;
|
|
|
-import java.nio.file.DirectoryNotEmptyException;
|
|
|
-import java.nio.file.DirectoryStream;
|
|
|
-import java.nio.file.Files;
|
|
|
-import java.nio.file.Path;
|
|
|
-import java.nio.file.Paths;
|
|
|
-
|
|
|
-import javax.inject.Inject;
|
|
|
-
|
|
|
import org.apache.commons.lang3.SystemUtils;
|
|
|
import org.cryptomator.common.settings.VaultSettings;
|
|
|
import org.cryptomator.cryptofs.CryptoFileSystem;
|
|
@@ -20,65 +11,84 @@ import org.cryptomator.frontend.fuse.mount.Mount;
|
|
|
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.DirectoryStream;
|
|
|
+import java.nio.file.FileAlreadyExistsException;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.nio.file.NotDirectoryException;
|
|
|
+import java.nio.file.Path;
|
|
|
+import java.nio.file.Paths;
|
|
|
+
|
|
|
public class FuseVolume implements Volume {
|
|
|
|
|
|
private static final Logger LOG = LoggerFactory.getLogger(FuseVolume.class);
|
|
|
|
|
|
- /**
|
|
|
- * TODO: dont use fixed Strings and rather set them in some system environment variables in the cryptomator installer and load those!
|
|
|
- */
|
|
|
+ // TODO: dont use fixed Strings and rather set them in some system environment variables in the cryptomator installer and load those!
|
|
|
private static final String DEFAULT_MOUNTROOTPATH_MAC = System.getProperty("user.home") + "/Library/Application Support/Cryptomator";
|
|
|
private static final String DEFAULT_MOUNTROOTPATH_LINUX = System.getProperty("user.home") + "/.Cryptomator";
|
|
|
+ private static final int MAX_TMPMOUNTPOINT_CREATION_RETRIES = 10;
|
|
|
|
|
|
private final VaultSettings vaultSettings;
|
|
|
|
|
|
private Mount fuseMnt;
|
|
|
- private Path mountPath;
|
|
|
- private boolean extraDirCreated;
|
|
|
+ private Path mountPoint;
|
|
|
+ private boolean createdTemporaryMountPoint;
|
|
|
|
|
|
@Inject
|
|
|
public FuseVolume(VaultSettings vaultSettings) {
|
|
|
this.vaultSettings = vaultSettings;
|
|
|
- this.extraDirCreated = false;
|
|
|
+ this.createdTemporaryMountPoint = false;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void mount(CryptoFileSystem fs) throws IOException, FuseNotSupportedException, VolumeException {
|
|
|
- String mountPath;
|
|
|
if (vaultSettings.usesIndividualMountPath().get()) {
|
|
|
- //specific path given
|
|
|
- mountPath = vaultSettings.individualMountPath().get();
|
|
|
+ Path customMountPoint = Paths.get(vaultSettings.individualMountPath().get());
|
|
|
+ checkProvidedMountPoint(customMountPoint);
|
|
|
+ this.mountPoint = customMountPoint;
|
|
|
+ LOG.debug("Successfully checked custom mount point: {}", mountPoint);
|
|
|
} else {
|
|
|
- //choose default path & create extra directory
|
|
|
- mountPath = createDirIfNotExist(SystemUtils.IS_OS_MAC ? DEFAULT_MOUNTROOTPATH_MAC : DEFAULT_MOUNTROOTPATH_LINUX, vaultSettings.mountName().get());
|
|
|
- extraDirCreated = true;
|
|
|
+ this.mountPoint = createTemporaryMountPoint();
|
|
|
+ createdTemporaryMountPoint = true;
|
|
|
+ LOG.debug("Successfully created mount point: {}", mountPoint);
|
|
|
}
|
|
|
- this.mountPath = Paths.get(mountPath).toAbsolutePath();
|
|
|
mount(fs.getPath("/"));
|
|
|
}
|
|
|
|
|
|
- private String createDirIfNotExist(String prefix, String dirName) throws IOException {
|
|
|
- Path p = Paths.get(prefix, dirName + vaultSettings.getId());
|
|
|
- if (Files.isDirectory(p)) {
|
|
|
- try (DirectoryStream<Path> emptyCheck = Files.newDirectoryStream(p)) {
|
|
|
- if (emptyCheck.iterator().hasNext()) {
|
|
|
- throw new DirectoryNotEmptyException("Mount point is not empty.");
|
|
|
- } else {
|
|
|
- LOG.info("Directory already exists and is empty. Using it as mount point.");
|
|
|
- return p.toString();
|
|
|
- }
|
|
|
+ private void checkProvidedMountPoint(Path mountPoint) throws IOException {
|
|
|
+ if (!Files.isDirectory(mountPoint)) {
|
|
|
+ throw new NotDirectoryException(mountPoint.toString());
|
|
|
+ }
|
|
|
+ try (DirectoryStream<Path> ds = Files.newDirectoryStream(mountPoint)) {
|
|
|
+ if (ds.iterator().hasNext()) {
|
|
|
+ throw new DirectoryNotEmptyException(mountPoint.toString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Path createTemporaryMountPoint() throws IOException {
|
|
|
+ Path parent = Paths.get(SystemUtils.IS_OS_MAC ? DEFAULT_MOUNTROOTPATH_MAC : DEFAULT_MOUNTROOTPATH_LINUX);
|
|
|
+ String basename = vaultSettings.getId();
|
|
|
+ for (int i = 0; i < MAX_TMPMOUNTPOINT_CREATION_RETRIES; i++) {
|
|
|
+ try {
|
|
|
+ Path mountPath = parent.resolve(basename + "_" + i);
|
|
|
+ Files.createDirectory(mountPath);
|
|
|
+ return mountPath;
|
|
|
+ } catch (FileAlreadyExistsException e) {
|
|
|
+ continue;
|
|
|
}
|
|
|
- } else {
|
|
|
- Files.createDirectory(p);
|
|
|
- return p.toString();
|
|
|
}
|
|
|
+ LOG.error("Failed to create mount path at {}/{}_x. Giving up after {} attempts.", parent, basename, MAX_TMPMOUNTPOINT_CREATION_RETRIES);
|
|
|
+ throw new FileAlreadyExistsException(parent.toString() + "/" + basename);
|
|
|
}
|
|
|
|
|
|
private void mount(Path root) throws VolumeException {
|
|
|
try {
|
|
|
- EnvironmentVariables envVars = EnvironmentVariables.create()
|
|
|
- .withMountName(vaultSettings.mountName().getValue())
|
|
|
- .withMountPath(mountPath)
|
|
|
+ EnvironmentVariables envVars = EnvironmentVariables.create() //
|
|
|
+ .withMountName(vaultSettings.mountName().getValue()) //
|
|
|
+ .withMountPath(mountPoint) //
|
|
|
.build();
|
|
|
this.fuseMnt = FuseMountFactory.getMounter().mount(root, envVars);
|
|
|
} catch (CommandFailedException e) {
|
|
@@ -91,7 +101,7 @@ public class FuseVolume implements Volume {
|
|
|
try {
|
|
|
fuseMnt.revealInFileManager();
|
|
|
} catch (CommandFailedException e) {
|
|
|
- LOG.info("Revealing the vault in file manger failed: " + e.getMessage());
|
|
|
+ LOG.debug("Revealing the vault in file manger failed: " + e.getMessage());
|
|
|
throw new VolumeException(e);
|
|
|
}
|
|
|
}
|
|
@@ -103,15 +113,16 @@ public class FuseVolume implements Volume {
|
|
|
} catch (CommandFailedException e) {
|
|
|
throw new VolumeException(e);
|
|
|
}
|
|
|
- cleanup();
|
|
|
+ deleteTemporaryMountPoint();
|
|
|
}
|
|
|
|
|
|
- private void cleanup() {
|
|
|
- if (extraDirCreated) {
|
|
|
+ private void deleteTemporaryMountPoint() {
|
|
|
+ if (createdTemporaryMountPoint) {
|
|
|
try {
|
|
|
- Files.delete(mountPath);
|
|
|
+ Files.delete(mountPoint);
|
|
|
+ LOG.debug("Successfully deleted mount point: {}", mountPoint);
|
|
|
} catch (IOException e) {
|
|
|
- LOG.warn("Could not delete mounting directory:" + e.getMessage());
|
|
|
+ LOG.warn("Could not delete mount point: {}", e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
}
|