mirror of
https://github.com/cryptomator/cryptomator.git
synced 2024-11-23 12:09:45 +00:00
directory moving
This commit is contained in:
parent
3d3c36b66f
commit
4cf872f916
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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)) {
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user