Explorar o código

Delete automatically generated mount point after locking, attempt to fix #773

Sebastian Stenzel %!s(int64=6) %!d(string=hai) anos
pai
achega
98cab7e4d8
Modificáronse 1 ficheiros con 55 adicións e 44 borrados
  1. 55 44
      main/ui/src/main/java/org/cryptomator/ui/model/FuseVolume.java

+ 55 - 44
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<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());
 			}
 		}
 	}