directory moving

This commit is contained in:
Sebastian Stenzel 2015-05-14 07:37:56 +02:00
parent 3d3c36b66f
commit 4cf872f916
4 changed files with 108 additions and 50 deletions

View File

@ -1,10 +1,21 @@
package org.cryptomator.webdav.jackrabbit;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.jackrabbit.webdav.DavResourceLocator;
@ -69,7 +80,7 @@ class CryptoLocator implements DavResourceLocator {
@Override
public String getRepositoryPath() {
if (isRootLocation()) {
return getDirectoryPath();
return getEncryptedRootDirectoryPath();
}
try {
final String plaintextPath = getResourcePath();
@ -88,18 +99,61 @@ class CryptoLocator implements DavResourceLocator {
* Returns the encrypted, absolute path on the local filesystem to the directory represented by this locator.
*
* @return Absolute, encrypted path as string (use {@link #getEncryptedDirectoryPath()} for {@link Path}s).
* @throws IOException
*/
public String getDirectoryPath() {
final String ciphertextPath = cryptor.encryptDirectoryPath(getResourcePath(), FileSystems.getDefault().getSeparator());
return rootPath.resolve(ciphertextPath).toString();
public String getDirectoryPath(boolean create) throws IOException {
if (isRootLocation()) {
return getEncryptedRootDirectoryPath();
} else {
final List<String> cleartextPathComponents = Arrays.asList(StringUtils.split(getResourcePath(), "/"));
return getEncryptedDirectoryPath(rootPath, cleartextPathComponents, false).toString();
}
}
private Path getEncryptedDirectoryPath(Path encryptedParentDirectoryPath, List<String> cleartextSubPathComponents, boolean create) throws IOException {
if (cleartextSubPathComponents.size() == 0) {
return encryptedParentDirectoryPath;
} else {
final String nextPathComponent = cleartextSubPathComponents.get(0);
final List<String> remainingSubPathComponents = cleartextSubPathComponents.subList(1, cleartextSubPathComponents.size());
final String fullEncryptedSubdirectoryPath = getEncryptedDirectoryPath(encryptedParentDirectoryPath, nextPathComponent, create);
return getEncryptedDirectoryPath(rootPath.resolve(fullEncryptedSubdirectoryPath), remainingSubPathComponents, create);
}
}
private String getEncryptedDirectoryPath(Path encryptedParentDirectoryPath, String cleartextDirectoryName, boolean create) throws IOException {
final String encryptedDirectoryName = this.cryptor.encryptFilename(cleartextDirectoryName, this.factory);
// TODO file extensions...
final Path directoryFile = encryptedParentDirectoryPath.resolve(encryptedDirectoryName + ".dir");
if (Files.exists(directoryFile)) {
try (final FileChannel c = FileChannel.open(directoryFile, StandardOpenOption.READ, StandardOpenOption.DSYNC); final FileLock lock = c.lock(0L, Long.MAX_VALUE, true)) {
final ByteBuffer buffer = ByteBuffer.allocate((int) c.size());
c.read(buffer);
final String directoryUuid = buffer.asCharBuffer().toString();
return this.cryptor.encryptDirectoryPath(directoryUuid, FileSystems.getDefault().getSeparator());
}
} else if (create) {
try (final FileChannel c = FileChannel.open(directoryFile, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.DSYNC); final FileLock lock = c.lock()) {
final String directoryUuid = UUID.randomUUID().toString();
final ByteBuffer buf = ByteBuffer.wrap(directoryUuid.getBytes(StandardCharsets.UTF_8));
c.write(buf);
return this.cryptor.encryptDirectoryPath(directoryUuid, FileSystems.getDefault().getSeparator());
}
} else {
throw new FileNotFoundException(directoryFile.toString());
}
}
private String getEncryptedRootDirectoryPath() {
return this.cryptor.encryptDirectoryPath("", FileSystems.getDefault().getSeparator());
}
public Path getEncryptedFilePath() {
return FileSystems.getDefault().getPath(getRepositoryPath());
}
public Path getEncryptedDirectoryPath() {
return FileSystems.getDefault().getPath(getDirectoryPath());
public Path getEncryptedDirectoryPath(boolean create) throws IOException {
return FileSystems.getDefault().getPath(getDirectoryPath(create));
}
/* other stuff */

View File

@ -1,5 +1,7 @@
package org.cryptomator.webdav.jackrabbit;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
@ -17,6 +19,7 @@ import org.apache.jackrabbit.webdav.DavSession;
import org.apache.jackrabbit.webdav.lock.LockManager;
import org.apache.jackrabbit.webdav.lock.SimpleLockManager;
import org.cryptomator.crypto.Cryptor;
import org.cryptomator.webdav.exceptions.IORuntimeException;
import org.eclipse.jetty.http.HttpHeader;
public class CryptoResourceFactory implements DavResourceFactory {
@ -52,10 +55,17 @@ public class CryptoResourceFactory implements DavResourceFactory {
private DavResource createResource(CryptoLocator locator, DavServletRequest request, DavServletResponse response) throws DavException {
final Path filepath = FileSystems.getDefault().getPath(locator.getRepositoryPath());
final Path dirpath = FileSystems.getDefault().getPath(locator.getDirectoryPath());
Path dirpath = null;
try {
dirpath = FileSystems.getDefault().getPath(locator.getDirectoryPath(DavMethods.METHOD_MKCOL.equals(request.getMethod())));
} catch (FileNotFoundException e) {
// no-op
} catch (IOException e) {
throw new IORuntimeException(e);
}
final String rangeHeader = request.getHeader(HttpHeader.RANGE.asString());
if (Files.isDirectory(dirpath) || DavMethods.METHOD_MKCOL.equals(request.getMethod())) {
if (Files.isDirectory(dirpath)) {
return createDirectory(locator, request.getDavSession());
} else if (Files.isRegularFile(filepath) && DavMethods.METHOD_GET.equals(request.getMethod()) && rangeHeader != null) {
response.setStatus(HttpStatus.SC_PARTIAL_CONTENT);
@ -69,7 +79,14 @@ public class CryptoResourceFactory implements DavResourceFactory {
private DavResource createResource(CryptoLocator locator, DavSession session) throws DavException {
final Path filepath = FileSystems.getDefault().getPath(locator.getRepositoryPath());
final Path dirpath = FileSystems.getDefault().getPath(locator.getDirectoryPath());
Path dirpath = null;
try {
dirpath = FileSystems.getDefault().getPath(locator.getDirectoryPath(false));
} catch (FileNotFoundException e) {
// no-op
} catch (IOException e) {
throw new IORuntimeException(e);
}
if (Files.isDirectory(dirpath)) {
return createDirectory(locator, session);

View File

@ -8,6 +8,7 @@
******************************************************************************/
package org.cryptomator.webdav.jackrabbit;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.AtomicMoveNotSupportedException;
@ -53,7 +54,11 @@ class EncryptedDir extends AbstractEncryptedNode {
@Override
protected Path getPhysicalPath() {
return locator.getEncryptedDirectoryPath();
try {
return locator.getEncryptedDirectoryPath(false);
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
@Override
@ -63,13 +68,17 @@ class EncryptedDir extends AbstractEncryptedNode {
@Override
public boolean exists() {
return Files.isDirectory(locator.getEncryptedDirectoryPath());
try {
return Files.isDirectory(locator.getEncryptedDirectoryPath(false));
} catch (IOException e) {
return false;
}
}
@Override
public long getModificationTime() {
try {
return Files.getLastModifiedTime(locator.getEncryptedDirectoryPath()).toMillis();
return Files.getLastModifiedTime(locator.getEncryptedDirectoryPath(false)).toMillis();
} catch (IOException e) {
return -1;
}
@ -94,8 +103,7 @@ class EncryptedDir extends AbstractEncryptedNode {
private void addMemberDir(CryptoLocator childLocator, InputContext inputContext) throws DavException {
try {
Files.createDirectories(childLocator.getEncryptedFilePath());
Files.createDirectories(childLocator.getEncryptedDirectoryPath());
Files.createDirectories(childLocator.getEncryptedDirectoryPath(true));
} catch (SecurityException e) {
throw new DavException(DavServletResponse.SC_FORBIDDEN, e);
} catch (IOException e) {
@ -126,7 +134,7 @@ class EncryptedDir extends AbstractEncryptedNode {
@Override
public DavResourceIterator getMembers() {
try {
final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(locator.getEncryptedDirectoryPath(), cryptor.getPayloadFilesFilter());
final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(locator.getEncryptedDirectoryPath(false), cryptor.getPayloadFilesFilter());
final List<DavResource> result = new ArrayList<>();
for (final Path childPath : directoryStream) {
@ -162,11 +170,13 @@ class EncryptedDir extends AbstractEncryptedNode {
private void removeMember(AbstractEncryptedNode member) {
try {
Files.deleteIfExists(member.getLocator().getEncryptedFilePath());
if (member.isCollection()) {
member.getMembers().forEachRemaining(m -> securelyRemoveMemberOfCollection(member, m));
Files.deleteIfExists(member.getLocator().getEncryptedDirectoryPath());
Files.deleteIfExists(member.getLocator().getEncryptedDirectoryPath(false));
}
Files.deleteIfExists(member.getLocator().getEncryptedFilePath());
} catch (FileNotFoundException e) {
// no-op
} catch (IOException e) {
throw new IORuntimeException(e);
}
@ -182,8 +192,8 @@ class EncryptedDir extends AbstractEncryptedNode {
@Override
public void move(AbstractEncryptedNode dest) throws DavException, IOException {
final Path srcDir = this.locator.getEncryptedDirectoryPath();
final Path dstDir = dest.locator.getEncryptedDirectoryPath();
final Path srcDir = this.locator.getEncryptedDirectoryPath(false);
final Path dstDir = dest.locator.getEncryptedDirectoryPath(true);
final Path srcFile = this.locator.getEncryptedFilePath();
final Path dstFile = dest.locator.getEncryptedFilePath();
@ -205,8 +215,8 @@ class EncryptedDir extends AbstractEncryptedNode {
@Override
public void copy(AbstractEncryptedNode dest, boolean shallow) throws DavException, IOException {
final Path srcDir = this.locator.getEncryptedDirectoryPath();
final Path dstDir = dest.locator.getEncryptedDirectoryPath();
final Path srcDir = this.locator.getEncryptedDirectoryPath(false);
final Path dstDir = dest.locator.getEncryptedDirectoryPath(true);
final Path srcFile = this.locator.getEncryptedFilePath();
final Path dstFile = dest.locator.getEncryptedFilePath();
@ -233,7 +243,12 @@ class EncryptedDir extends AbstractEncryptedNode {
@Override
protected void determineProperties() {
final Path path = locator.getEncryptedDirectoryPath();
Path path;
try {
path = locator.getEncryptedDirectoryPath(false);
} catch (IOException e) {
throw new IORuntimeException(e);
}
properties.add(new ResourceType(ResourceType.COLLECTION));
properties.add(new DefaultDavProperty<Integer>(DavPropertyName.ISCOLLECTION, 1));
if (Files.exists(path)) {

View File

@ -1,28 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 Sebastian Stenzel
* This file is licensed under the terms of the MIT license.
* See the LICENSE.txt file for more info.
*
* Contributors:
* Sebastian Stenzel - initial API and implementation
******************************************************************************/
package org.cryptomator.webdav.jackrabbit;
import java.nio.file.FileSystems;
import java.nio.file.Path;
final class ResourcePathUtils {
private ResourcePathUtils() {
throw new IllegalStateException("not instantiable");
}
public static Path getPhysicalFilePath(CryptoLocator locator) {
return FileSystems.getDefault().getPath(locator.getRepositoryPath());
}
public static Path getPhysicalDirectoryPath(CryptoLocator locator) {
return FileSystems.getDefault().getPath(locator.getDirectoryPath());
}
}