FileUtils.doCopyFile(File, File, boolean) can throw
ClosedByInterruptException.
MODIFY
src/changes/changes.xml
src/changes/changes.xml
@@ -89,6 +89,9 @@ The <action> type attribute can be add,update,fix,remove.
<action issue="IO-594" dev="ggregory" type="add" due-to="Gary Gregory">
Add IOUtils copy methods with java.lang.Appendable as the target.
</action>
+ <action issue="IO-604" dev="ggregory" type="fix" due-to="Gary Gregory">
+ FileUtils.doCopyFile(File, File, boolean) can throw ClosedByInterruptException.
+ </action>
</release>
<release version="2.6" date="2017-10-15" description="Java 7 required, Java 9 supported.">

MODIFY
src/main/java/org/apache/commons/io/FileUtils.java
src/main/java/org/apache/commons/io/FileUtils.java
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
@@ -1107,7 +1109,7 @@ public static long copyFile(final File input, final OutputStream output) throws
/**
* Internal copy file method.
- * This caches the original file length, and throws an IOException
+ * This uses the original file length, and throws an IOException
* if the output file length is different from the current input file length.
* So it may fail if the file changes size.
* It may also fail with "IllegalArgumentException: Negative size" if the input file is truncated part way
@@ -1128,32 +1130,24 @@ private static void doCopyFile(final File srcFile, final File destFile, final bo
throw new IOException("Destination '" + destFile + "' exists but is a directory");
}
- try (FileInputStream fis = new FileInputStream(srcFile);
- FileChannel input = fis.getChannel();
- FileOutputStream fos = new FileOutputStream(destFile);
- FileChannel output = fos.getChannel()) {
- final long size = input.size(); // TODO See IO-386
- long pos = 0;
- long count = 0;
- while (pos < size) {
- final long remain = size - pos;
- count = remain > FILE_COPY_BUFFER_SIZE ? FILE_COPY_BUFFER_SIZE : remain;
- final long bytesCopied = output.transferFrom(input, pos, count);
- if (bytesCopied == 0) { // IO-385 - can happen if file is truncated after caching the size
- break; // ensure we don't loop forever
- }
- pos += bytesCopied;
- }
+ Path srcPath = srcFile.toPath();
+ Path destPath = destFile.toPath();
+ final long newLastModifed = preserveFileDate ? srcFile.lastModified() : destFile.lastModified();
+ Files.copy(srcPath, destPath, StandardCopyOption.REPLACE_EXISTING);
+
+ // TODO IO-386: Do we still need this check?
+ checkEqualSizes(srcFile, destFile, Files.size(srcPath), Files.size(destPath));
+ // TODO IO-386: Do we still need this check?
+ checkEqualSizes(srcFile, destFile, srcFile.length(), destFile.length());
+
+ destFile.setLastModified(newLastModifed);
}
- final long srcLen = srcFile.length(); // TODO See IO-386
- final long dstLen = destFile.length(); // TODO See IO-386
+ private static void checkEqualSizes(final File srcFile, final File destFile, final long srcLen, final long dstLen)
+ throws IOException {
if (srcLen != dstLen) {
- throw new IOException("Failed to copy full contents from '" +
- srcFile + "' to '" + destFile + "' Expected length: " + srcLen + " Actual: " + dstLen);
- }
- if (preserveFileDate) {
- destFile.setLastModified(srcFile.lastModified());
+ throw new IOException("Failed to copy full contents from '" + srcFile + "' to '" + destFile
+ + "' Expected length: " + srcLen + " Actual: " + dstLen);
}
}

[IO-604] FileUtils.doCopyFile(File, File, boolean) can throw
ClosedByInterruptException.