mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-08-17 12:46:01 +00:00
small I/O tweaks
This commit is contained in:
@@ -19,6 +19,8 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -155,8 +157,10 @@ class EncryptedDir extends AbstractEncryptedNode implements FileConstants {
|
||||
final String cleartextFilename = FilenameUtils.getName(childLocator.getResourcePath());
|
||||
final String ciphertextFilename = filenameTranslator.getEncryptedFilename(cleartextFilename);
|
||||
final Path filePath = dirPath.resolve(ciphertextFilename);
|
||||
try (final FileChannel c = FileChannel.open(filePath, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
final SilentlyFailingFileLock lock = new SilentlyFailingFileLock(c, 0L, FILE_HEADER_LENGTH, false)) {
|
||||
final Path tmpFilePath = Files.createTempFile(dirPath, null, null);
|
||||
// encrypt to tmp file:
|
||||
try (final FileChannel c = FileChannel.open(tmpFilePath, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
final SilentlyFailingFileLock lock = new SilentlyFailingFileLock(c, false)) {
|
||||
cryptor.encryptFile(inputContext.getInputStream(), c);
|
||||
} catch (SecurityException e) {
|
||||
throw new DavException(DavServletResponse.SC_FORBIDDEN, e);
|
||||
@@ -169,6 +173,13 @@ class EncryptedDir extends AbstractEncryptedNode implements FileConstants {
|
||||
} finally {
|
||||
IOUtils.closeQuietly(inputContext.getInputStream());
|
||||
}
|
||||
// mv tmp to target file:
|
||||
try {
|
||||
Files.move(tmpFilePath, filePath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
|
||||
} catch (AtomicMoveNotSupportedException e) {
|
||||
Files.move(tmpFilePath, filePath, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
Files.setLastModifiedTime(filePath, FileTime.from(Instant.now()));
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to create file.", e);
|
||||
throw new IORuntimeException(e);
|
||||
|
||||
@@ -109,6 +109,7 @@ class EncryptedFile extends AbstractEncryptedNode implements FileConstants {
|
||||
final boolean authenticate = !cryptoWarningHandler.ignoreMac(getLocator().getResourcePath());
|
||||
cryptor.decryptFile(c, outputContext.getOutputStream(), authenticate);
|
||||
}
|
||||
outputContext.getOutputStream().flush();
|
||||
} catch (EOFException e) {
|
||||
LOG.warn("Unexpected end of stream (possibly client hung up).");
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ class EncryptedFilePart extends EncryptedFile {
|
||||
final boolean authenticate = !cryptoWarningHandler.ignoreMac(getLocator().getResourcePath());
|
||||
cryptor.decryptRange(c, outputContext.getOutputStream(), range.getLeft(), rangeLength, authenticate);
|
||||
}
|
||||
outputContext.getOutputStream().flush();
|
||||
} catch (EOFException e) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.trace("Unexpected end of stream during delivery of partial content (client hung up).");
|
||||
|
||||
@@ -311,7 +311,7 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
|
||||
// read header:
|
||||
encryptedFile.position(0);
|
||||
final ByteBuffer headerBuf = ByteBuffer.allocate(104);
|
||||
final int headerBytesRead = encryptedFile.read(headerBuf);
|
||||
final int headerBytesRead = readFromChannel(encryptedFile, headerBuf);
|
||||
if (headerBytesRead != headerBuf.capacity()) {
|
||||
return null;
|
||||
}
|
||||
@@ -373,7 +373,7 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
|
||||
// read header:
|
||||
encryptedFile.position(0l);
|
||||
final ByteBuffer headerBuf = ByteBuffer.allocate(104);
|
||||
final int headerBytesRead = encryptedFile.read(headerBuf);
|
||||
final int headerBytesRead = readFromChannel(encryptedFile, headerBuf);
|
||||
if (headerBytesRead != headerBuf.capacity()) {
|
||||
throw new IOException("Failed to read file header.");
|
||||
}
|
||||
@@ -474,7 +474,7 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
|
||||
}
|
||||
final int inBufSize = numBlocks * (CONTENT_MAC_BLOCK + 32);
|
||||
final ByteBuffer buf = ByteBuffer.allocate(inBufSize);
|
||||
bytesRead = encryptedFile.read(buf);
|
||||
bytesRead = readFromChannel(encryptedFile, buf);
|
||||
buf.flip();
|
||||
final int blocksRead = (int) Math.ceil(bytesRead / (double) (CONTENT_MAC_BLOCK + 32));
|
||||
final boolean consumedInTime = executor.offer(new BlocksData(buf.asReadOnlyBuffer(), blockNumber, blocksRead), 1, TimeUnit.SECONDS);
|
||||
@@ -508,7 +508,7 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
|
||||
// read header:
|
||||
encryptedFile.position(0l);
|
||||
final ByteBuffer headerBuf = ByteBuffer.allocate(104);
|
||||
final int headerBytesRead = encryptedFile.read(headerBuf);
|
||||
final int headerBytesRead = readFromChannel(encryptedFile, headerBuf);
|
||||
if (headerBytesRead != headerBuf.capacity()) {
|
||||
throw new IOException("Failed to read file header.");
|
||||
}
|
||||
@@ -685,7 +685,7 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
|
||||
}
|
||||
final int inBufSize = numBlocks * CONTENT_MAC_BLOCK;
|
||||
final ByteBuffer inBuf = ByteBuffer.allocate(inBufSize);
|
||||
bytesRead = channel.read(inBuf);
|
||||
bytesRead = readFromChannel(channel, inBuf);
|
||||
inBuf.flip();
|
||||
final int blocksRead = (int) Math.ceil(bytesRead / (double) CONTENT_MAC_BLOCK);
|
||||
final boolean consumedInTime = executor.offer(new BlocksData(inBuf.asReadOnlyBuffer(), blockNumber, blocksRead), 1, TimeUnit.SECONDS);
|
||||
@@ -736,4 +736,29 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
|
||||
return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(lng).array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads bytes from a ReadableByteChannel.
|
||||
* <p>
|
||||
* This implementation guarantees that it will read as many bytes
|
||||
* as possible before giving up; this may not always be the case for
|
||||
* subclasses of {@link ReadableByteChannel}.
|
||||
*
|
||||
* @param input the byte channel to read
|
||||
* @param buffer byte buffer destination
|
||||
* @return the actual length read; may be less than requested if EOF was reached
|
||||
* @throws IOException if a read error occurs
|
||||
* @see
|
||||
* <a href="http://commons.apache.org/proper/commons-io/apidocs/src-html/org/apache/commons/io/IOUtils.html">Apache Commons IOUtils 2.5</a>
|
||||
*/
|
||||
public static int readFromChannel(final ReadableByteChannel input, final ByteBuffer buffer) throws IOException {
|
||||
final int length = buffer.remaining();
|
||||
while (buffer.remaining() > 0) {
|
||||
final int count = input.read(buffer);
|
||||
if (count == -1) { // EOF
|
||||
break;
|
||||
}
|
||||
}
|
||||
return length - buffer.remaining();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user