small I/O tweaks

This commit is contained in:
Sebastian Stenzel
2015-08-25 10:55:46 +02:00
parent 71983cc3a8
commit 6b073c1499
4 changed files with 45 additions and 7 deletions
@@ -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();
}
}