From 98cab7e4d89ef6b2d18fc25fb8b240c35d96a906 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 31 Jan 2019 15:38:05 +0100 Subject: [PATCH] Delete automatically generated mount point after locking, attempt to fix #773 --- .../org/cryptomator/ui/model/FuseVolume.java | 101 ++++++++++-------- 1 file changed, 56 insertions(+), 45 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/FuseVolume.java b/main/ui/src/main/java/org/cryptomator/ui/model/FuseVolume.java index ec63da443..972b9ce06 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/FuseVolume.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/FuseVolume.java @@ -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 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(); - } - } - } else { - Files.createDirectory(p); - return p.toString(); + private void checkProvidedMountPoint(Path mountPoint) throws IOException { + if (!Files.isDirectory(mountPoint)) { + throw new NotDirectoryException(mountPoint.toString()); } + try (DirectoryStream 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; + } + } + 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()); } } }