Browse Source

Creating directories lazily now. This fixes an issue, where a "ui" folder appeared inside the vault, just because Windows Explorer queries the existence of "ui/SwDRM.dll".

Sebastian Stenzel 9 years ago
parent
commit
3f946d1c82

+ 66 - 51
main/core/src/main/java/org/cryptomator/webdav/jackrabbit/CryptoResourceFactory.java

@@ -24,6 +24,7 @@ import org.apache.jackrabbit.webdav.lock.LockManager;
 import org.apache.jackrabbit.webdav.lock.SimpleLockManager;
 import org.apache.logging.log4j.util.Strings;
 import org.cryptomator.crypto.Cryptor;
+import org.cryptomator.webdav.exceptions.IORuntimeException;
 import org.eclipse.jetty.http.HttpHeader;
 
 public class CryptoResourceFactory implements DavResourceFactory, FileConstants {
@@ -52,34 +53,36 @@ public class CryptoResourceFactory implements DavResourceFactory, FileConstants
 			return createRootDirectory(locator, request.getDavSession());
 		}
 
-		final Path filePath = getEncryptedFilePath(locator.getResourcePath());
-		final Path dirFilePath = getEncryptedDirectoryFilePath(locator.getResourcePath());
-		final String rangeHeader = request.getHeader(HttpHeader.RANGE.asString());
-		final String ifRangeHeader = request.getHeader(HttpHeader.IF_RANGE.asString());
-		if (Files.exists(dirFilePath) || DavMethods.METHOD_MKCOL.equals(request.getMethod())) {
-			// DIRECTORY
-			return createDirectory(locator, request.getDavSession(), dirFilePath);
-		} else if (Files.exists(filePath) && DavMethods.METHOD_GET.equals(request.getMethod()) && rangeHeader != null && isRangeSatisfiable(rangeHeader) && isIfRangePreconditionFulfilled(ifRangeHeader, filePath)) {
-			// FILE RANGE
-			final Pair<String, String> requestRange = getRequestRange(rangeHeader);
-			response.setStatus(DavServletResponse.SC_PARTIAL_CONTENT);
-			return createFilePart(locator, request.getDavSession(), requestRange, filePath);
-		} else if (Files.exists(filePath) && DavMethods.METHOD_GET.equals(request.getMethod()) && rangeHeader != null && isRangeSatisfiable(rangeHeader) && !isIfRangePreconditionFulfilled(ifRangeHeader, filePath)) {
-			// FULL FILE (if-range not fulfilled)
-			return createFile(locator, request.getDavSession(), filePath);
-		} else if (Files.exists(filePath) && DavMethods.METHOD_GET.equals(request.getMethod()) && rangeHeader != null && !isRangeSatisfiable(rangeHeader)) {
-			// FULL FILE (unsatisfiable range)
-			response.setStatus(DavServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
-			final EncryptedFile file = createFile(locator, request.getDavSession(), filePath);
-			response.addHeader(HttpHeader.CONTENT_RANGE.asString(), "bytes */" + file.getContentLength());
-			return file;
-		} else if (Files.exists(filePath) || DavMethods.METHOD_PUT.equals(request.getMethod())) {
-			// FULL FILE (as requested)
-			return createFile(locator, request.getDavSession(), filePath);
-		} else {
-			// NO FILE OR FOLDER (e.g. for MOVE operations):
-			return createNonExisting(locator, request.getDavSession(), filePath, dirFilePath);
+		try {
+			final Path filePath = getEncryptedFilePath(locator.getResourcePath(), false);
+			final Path dirFilePath = getEncryptedDirectoryFilePath(locator.getResourcePath(), false);
+			final String rangeHeader = request.getHeader(HttpHeader.RANGE.asString());
+			final String ifRangeHeader = request.getHeader(HttpHeader.IF_RANGE.asString());
+			if (Files.exists(dirFilePath) || DavMethods.METHOD_MKCOL.equals(request.getMethod())) {
+				// DIRECTORY
+				return createDirectory(locator, request.getDavSession(), dirFilePath);
+			} else if (Files.exists(filePath) && DavMethods.METHOD_GET.equals(request.getMethod()) && rangeHeader != null && isRangeSatisfiable(rangeHeader) && isIfRangePreconditionFulfilled(ifRangeHeader, filePath)) {
+				// FILE RANGE
+				final Pair<String, String> requestRange = getRequestRange(rangeHeader);
+				response.setStatus(DavServletResponse.SC_PARTIAL_CONTENT);
+				return createFilePart(locator, request.getDavSession(), requestRange, filePath);
+			} else if (Files.exists(filePath) && DavMethods.METHOD_GET.equals(request.getMethod()) && rangeHeader != null && isRangeSatisfiable(rangeHeader) && !isIfRangePreconditionFulfilled(ifRangeHeader, filePath)) {
+				// FULL FILE (if-range not fulfilled)
+				return createFile(locator, request.getDavSession(), filePath);
+			} else if (Files.exists(filePath) && DavMethods.METHOD_GET.equals(request.getMethod()) && rangeHeader != null && !isRangeSatisfiable(rangeHeader)) {
+				// FULL FILE (unsatisfiable range)
+				response.setStatus(DavServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
+				final EncryptedFile file = createFile(locator, request.getDavSession(), filePath);
+				response.addHeader(HttpHeader.CONTENT_RANGE.asString(), "bytes */" + file.getContentLength());
+				return file;
+			} else if (Files.exists(filePath) || DavMethods.METHOD_PUT.equals(request.getMethod())) {
+				// FULL FILE (as requested)
+				return createFile(locator, request.getDavSession(), filePath);
+			}
+		} catch (NonExistingParentException e) {
+			// return non-existing
 		}
+		return createNonExisting(locator, request.getDavSession());
 	}
 
 	@Override
@@ -88,16 +91,18 @@ public class CryptoResourceFactory implements DavResourceFactory, FileConstants
 			return createRootDirectory(locator, session);
 		}
 
-		final Path filePath = getEncryptedFilePath(locator.getResourcePath());
-		final Path dirFilePath = getEncryptedDirectoryFilePath(locator.getResourcePath());
-		if (Files.exists(dirFilePath)) {
-			return createDirectory(locator, session, dirFilePath);
-		} else if (Files.exists(filePath)) {
-			return createFile(locator, session, filePath);
-		} else {
-			// e.g. for MOVE operations:
-			return createNonExisting(locator, session, filePath, dirFilePath);
+		try {
+			final Path filePath = getEncryptedFilePath(locator.getResourcePath(), false);
+			final Path dirFilePath = getEncryptedDirectoryFilePath(locator.getResourcePath(), false);
+			if (Files.exists(dirFilePath)) {
+				return createDirectory(locator, session, dirFilePath);
+			} else if (Files.exists(filePath)) {
+				return createFile(locator, session, filePath);
+			}
+		} catch (NonExistingParentException e) {
+			// return non-existing
 		}
+		return createNonExisting(locator, session);
 	}
 
 	DavResource createChildDirectoryResource(DavResourceLocator locator, DavSession session, Path existingDirectoryFile) throws DavException {
@@ -176,41 +181,42 @@ public class CryptoResourceFactory implements DavResourceFactory, FileConstants
 
 	/**
 	 * @return Absolute file path for a given cleartext file resourcePath.
-	 * @throws IOException
+	 * @throws NonExistingParentException If one ancestor of the enrypted path is missing
 	 */
-	private Path getEncryptedFilePath(String relativeCleartextPath) throws DavException {
+	Path getEncryptedFilePath(String relativeCleartextPath, boolean createNonExisting) throws NonExistingParentException {
 		final String parentCleartextPath = FilenameUtils.getPathNoEndSeparator(relativeCleartextPath);
-		final Path parent = createEncryptedDirectoryPath(parentCleartextPath);
+		final Path parent = getEncryptedDirectoryPath(parentCleartextPath, createNonExisting);
 		final String cleartextFilename = FilenameUtils.getName(relativeCleartextPath);
 		try {
 			final String encryptedFilename = filenameTranslator.getEncryptedFilename(cleartextFilename);
 			return parent.resolve(encryptedFilename);
 		} catch (IOException e) {
-			throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, e);
+			throw new IORuntimeException(e);
 		}
 	}
 
 	/**
 	 * @return Absolute file path for a given cleartext file resourcePath.
-	 * @throws IOException
+	 * @throws NonExistingParentException If one ancestor of the enrypted path is missing
 	 */
-	private Path getEncryptedDirectoryFilePath(String relativeCleartextPath) throws DavException {
+	Path getEncryptedDirectoryFilePath(String relativeCleartextPath, boolean createNonExisting) throws NonExistingParentException {
 		final String parentCleartextPath = FilenameUtils.getPathNoEndSeparator(relativeCleartextPath);
-		final Path parent = createEncryptedDirectoryPath(parentCleartextPath);
+		final Path parent = getEncryptedDirectoryPath(parentCleartextPath, createNonExisting);
 		final String cleartextFilename = FilenameUtils.getName(relativeCleartextPath);
 		try {
 			final String encryptedFilename = filenameTranslator.getEncryptedDirFileName(cleartextFilename);
 			return parent.resolve(encryptedFilename);
 		} catch (IOException e) {
-			throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, e);
+			throw new IORuntimeException(e);
 		}
 	}
-
+	
 	/**
+	 * @param createNonExisting if <code>false</code>, a {@link NonExistingParentException} will be thrown for missing ancestors.
 	 * @return Absolute directory path for a given cleartext directory resourcePath.
-	 * @throws IOException
+	 * @throws NonExistingParentException if one ancestor directory is missing.
 	 */
-	private Path createEncryptedDirectoryPath(String relativeCleartextPath) throws DavException {
+	private Path getEncryptedDirectoryPath(String relativeCleartextPath, boolean createNonExisting) throws NonExistingParentException {
 		assert Strings.isEmpty(relativeCleartextPath) || !relativeCleartextPath.endsWith("/");
 		try {
 			final Path result;
@@ -220,10 +226,13 @@ public class CryptoResourceFactory implements DavResourceFactory, FileConstants
 				result = dataRoot.resolve(fixedRootDirectory);
 			} else {
 				final String parentCleartextPath = FilenameUtils.getPathNoEndSeparator(relativeCleartextPath);
-				final Path parent = createEncryptedDirectoryPath(parentCleartextPath);
+				final Path parent = getEncryptedDirectoryPath(parentCleartextPath, createNonExisting);
 				final String cleartextFilename = FilenameUtils.getName(relativeCleartextPath);
 				final String encryptedFilename = filenameTranslator.getEncryptedDirFileName(cleartextFilename);
 				final Path directoryFile = parent.resolve(encryptedFilename);
+				if (!createNonExisting && !Files.exists(directoryFile)) {
+					throw new NonExistingParentException();
+				}
 				final String directoryId = filenameTranslator.getDirectoryId(directoryFile, true);
 				final String directory = cryptor.encryptDirectoryPath(directoryId, FileSystems.getDefault().getSeparator());
 				result = dataRoot.resolve(directory);
@@ -231,7 +240,7 @@ public class CryptoResourceFactory implements DavResourceFactory, FileConstants
 			Files.createDirectories(result);
 			return result;
 		} catch (IOException e) {
-			throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, e);
+			throw new IORuntimeException(e);
 		}
 	}
 
@@ -263,8 +272,14 @@ public class CryptoResourceFactory implements DavResourceFactory, FileConstants
 		return new EncryptedDir(this, locator, session, lockManager, cryptor, filenameTranslator, filePath);
 	}
 
-	private NonExistingNode createNonExisting(DavResourceLocator locator, DavSession session, Path filePath, Path dirFilePath) {
-		return new NonExistingNode(this, locator, session, lockManager, cryptor, filePath, dirFilePath);
+	private NonExistingNode createNonExisting(DavResourceLocator locator, DavSession session) {
+		return new NonExistingNode(this, locator, session, lockManager, cryptor);
+	}
+	
+	static class NonExistingParentException extends Exception {
+		
+		private static final long serialVersionUID = 4421121746624627094L;
+		
 	}
 
 }

+ 2 - 2
main/core/src/main/java/org/cryptomator/webdav/jackrabbit/EncryptedDir.java

@@ -260,7 +260,7 @@ class EncryptedDir extends AbstractEncryptedNode implements FileConstants {
 		final Path srcPath = filePath;
 		final Path dstPath;
 		if (dest instanceof NonExistingNode) {
-			dstPath = ((NonExistingNode) dest).getDirFilePath();
+			dstPath = ((NonExistingNode) dest).materializeDirFilePath();
 		} else {
 			dstPath = dest.filePath;
 		}
@@ -278,7 +278,7 @@ class EncryptedDir extends AbstractEncryptedNode implements FileConstants {
 	public void copy(AbstractEncryptedNode dest, boolean shallow) throws DavException, IOException {
 		final Path dstDirFilePath;
 		if (dest instanceof NonExistingNode) {
-			dstDirFilePath = ((NonExistingNode) dest).getDirFilePath();
+			dstDirFilePath = ((NonExistingNode) dest).materializeDirFilePath();
 		} else {
 			dstDirFilePath = dest.filePath;
 		}

+ 2 - 2
main/core/src/main/java/org/cryptomator/webdav/jackrabbit/EncryptedFile.java

@@ -120,7 +120,7 @@ class EncryptedFile extends AbstractEncryptedNode implements FileConstants {
 		final Path srcPath = filePath;
 		final Path dstPath;
 		if (dest instanceof NonExistingNode) {
-			dstPath = ((NonExistingNode) dest).getFilePath();
+			dstPath = ((NonExistingNode) dest).materializeFilePath();
 		} else {
 			dstPath = dest.filePath;
 		}
@@ -137,7 +137,7 @@ class EncryptedFile extends AbstractEncryptedNode implements FileConstants {
 		final Path srcPath = filePath;
 		final Path dstPath;
 		if (dest instanceof NonExistingNode) {
-			dstPath = ((NonExistingNode) dest).getFilePath();
+			dstPath = ((NonExistingNode) dest).materializeFilePath();
 		} else {
 			dstPath = dest.filePath;
 		}

+ 20 - 10
main/core/src/main/java/org/cryptomator/webdav/jackrabbit/NonExistingNode.java

@@ -21,16 +21,12 @@ import org.apache.jackrabbit.webdav.io.OutputContext;
 import org.apache.jackrabbit.webdav.lock.LockManager;
 import org.apache.jackrabbit.webdav.property.DavProperty;
 import org.cryptomator.crypto.Cryptor;
+import org.cryptomator.webdav.jackrabbit.CryptoResourceFactory.NonExistingParentException;
 
 class NonExistingNode extends AbstractEncryptedNode {
 
-	private final Path filePath;
-	private final Path dirFilePath;
-
-	public NonExistingNode(CryptoResourceFactory factory, DavResourceLocator locator, DavSession session, LockManager lockManager, Cryptor cryptor, Path filePath, Path dirFilePath) {
+	public NonExistingNode(CryptoResourceFactory factory, DavResourceLocator locator, DavSession session, LockManager lockManager, Cryptor cryptor) {
 		super(factory, locator, session, lockManager, cryptor, null);
-		this.filePath = filePath;
-		this.dirFilePath = dirFilePath;
 	}
 
 	@Override
@@ -83,12 +79,26 @@ class NonExistingNode extends AbstractEncryptedNode {
 		throw new UnsupportedOperationException("Resource doesn't exist.");
 	}
 
-	public Path getFilePath() {
-		return filePath;
+	/**
+	 * @return lazily resolved file path, e.g. needed during MOVE operations.
+	 */
+	public Path materializeFilePath() {
+		try {
+			return factory.getEncryptedFilePath(locator.getResourcePath(), true);
+		} catch (NonExistingParentException e) {
+			throw new IllegalStateException(e);
+		}
 	}
 
-	public Path getDirFilePath() {
-		return dirFilePath;
+	/**
+	 * @return lazily resolved directory file path, e.g. needed during MOVE operations.
+	 */
+	public Path materializeDirFilePath() {
+		try {
+			return factory.getEncryptedDirectoryFilePath(locator.getResourcePath(), true);
+		} catch (NonExistingParentException e) {
+			throw new IllegalStateException(e);
+		}
 	}
 
 }