You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by ja...@apache.org on 2019/02/01 07:40:19 UTC
[ant-ivy] branch master updated: IVY-1602 Prevent cache corruption
when attempting to copy a file to a destination which resolves back to the
same source file
This is an automated email from the ASF dual-hosted git repository.
jaikiran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ant-ivy.git
The following commit(s) were added to refs/heads/master by this push:
new 75d8d79 IVY-1602 Prevent cache corruption when attempting to copy a file to a destination which resolves back to the same source file
75d8d79 is described below
commit 75d8d7980628ec8ae5b149fa49a4d8de6a14417c
Author: Jaikiran Pai <ja...@apache.org>
AuthorDate: Fri Feb 1 11:40:35 2019 +0530
IVY-1602 Prevent cache corruption when attempting to copy a file to a destination which resolves back to the same source file
---
src/java/org/apache/ivy/util/FileUtil.java | 24 +++++++++
test/java/org/apache/ivy/ant/FileUtilTest.java | 68 ++++++++++++++++++++++++++
2 files changed, 92 insertions(+)
diff --git a/src/java/org/apache/ivy/util/FileUtil.java b/src/java/org/apache/ivy/util/FileUtil.java
index 9c780f2..c845364 100644
--- a/src/java/org/apache/ivy/util/FileUtil.java
+++ b/src/java/org/apache/ivy/util/FileUtil.java
@@ -34,6 +34,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -104,6 +105,16 @@ public final class FileUtil {
return true;
}
+ /**
+ * This is the same as calling {@link #copy(File, File, CopyProgressListener, boolean)} with
+ * {@code overwrite} param as {@code true}
+ *
+ * @param src The source to copy
+ * @param dest The destination
+ * @param l A {@link CopyProgressListener}. Can be null
+ * @return Returns true if the file was copied. Else returns false
+ * @throws IOException If any exception occurs during the copy operation
+ */
public static boolean copy(File src, File dest, CopyProgressListener l) throws IOException {
return copy(src, dest, l, false);
}
@@ -163,6 +174,19 @@ public final class FileUtil {
return deepCopy(src, dest, l, overwrite);
}
// else it is a file copy
+ // check if it's the same file (the src and the dest). if they are the same, skip the copy
+ try {
+ if (Files.isSameFile(src.toPath(), dest.toPath())) {
+ Message.verbose("Skipping copy of file " + src + " to " + dest + " since they are the same file");
+ // we consider the file as copied if overwrite is true
+ return overwrite;
+ }
+ } catch (NoSuchFileException nsfe) {
+ // ignore and move on and attempt the copy
+ } catch (IOException ioe) {
+ // log and move on and attempt the copy
+ Message.verbose("Could not determine if " + src + " and dest " + dest + " are the same file", ioe);
+ }
copy(new FileInputStream(src), dest, l);
long srcLen = src.length();
long destLen = dest.length();
diff --git a/test/java/org/apache/ivy/ant/FileUtilTest.java b/test/java/org/apache/ivy/ant/FileUtilTest.java
index 7eb28d6..a3ca469 100644
--- a/test/java/org/apache/ivy/ant/FileUtilTest.java
+++ b/test/java/org/apache/ivy/ant/FileUtilTest.java
@@ -17,10 +17,21 @@
*/
package org.apache.ivy.ant;
+import org.apache.ivy.util.CopyProgressListener;
import org.apache.ivy.util.FileUtil;
+import org.apache.ivy.util.Message;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.BeforeClass;
import org.junit.Test;
import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -33,6 +44,24 @@ import static org.junit.Assert.assertTrue;
*/
public class FileUtilTest {
+ private static boolean symlinkCapable = false;
+
+ @BeforeClass
+ public static void beforeClass() {
+ try {
+ final Path tmpFile = Files.createTempFile(null, null);
+ tmpFile.toFile().deleteOnExit();
+ final Path symlink = Files.createSymbolicLink(Paths.get(Files.createTempDirectory(null).toString(),
+ "symlink-test-file"), tmpFile);
+ symlinkCapable = true;
+ symlink.toFile().deleteOnExit();
+ } catch (IOException ioe) {
+ // ignore and move on
+ symlinkCapable = false;
+ Message.info("Current system isn't considered to have symlink capability due to ", ioe);
+ }
+ }
+
/**
* Tests that {@link FileUtil#normalize(String)} works as expected for some basic file paths
*/
@@ -83,4 +112,43 @@ public class FileUtilTest {
}
}
+ /**
+ * Tests that the call to {@link FileUtil#copy(File, File, CopyProgressListener)} doesn't corrupt
+ * the source file if the destination file resolves back to the source file being copied
+ *
+ * @throws Exception
+ * @see <a href="https://issues.apache.org/jira/browse/IVY-1602">IVY-1602</a> for more details
+ */
+ @Test
+ public void testCopyOfSameFile() throws Exception {
+ Assume.assumeTrue("Skipping test due to system not having symlink capability", symlinkCapable);
+ final Path srcDir = Files.createTempDirectory(null);
+ srcDir.toFile().deleteOnExit();
+ // create a src file
+ final Path srcFile = Paths.get(srcDir.toString(), "helloworld.txt");
+ srcFile.toFile().deleteOnExit();
+ final byte[] fileContent = "Hello world!!!".getBytes(StandardCharsets.UTF_8);
+ Files.write(srcFile, fileContent);
+
+ final Path destDir = Paths.get(Files.createTempDirectory(null).toString(), "symlink-dest");
+ destDir.toFile().deleteOnExit();
+ // now create a symlink to the dir containing the src file we intend to copy later
+ Files.createSymbolicLink(destDir, srcDir);
+ // at this point destDir is a symlink to the srcDir and the srcDir contains the srcFile.
+ // we now attempt to copy the srcFile to a destination which resolves back the same srcFile
+ final Path destFile = Paths.get(destDir.toString(), srcFile.getFileName().toString());
+ FileUtil.copy(srcFile.toFile(), destFile.toFile(), null, false);
+ // make sure the copy didn't corrupt the source file
+ Assert.assertTrue("Unexpected content in source file " + srcFile, Arrays.equals(fileContent, Files.readAllBytes(srcFile)));
+ // also check the dest file has the same content as source file after the copy operation
+ Assert.assertTrue("Unexpected content in dest file " + destFile, Arrays.equals(fileContent, Files.readAllBytes(destFile)));
+
+ // do the same tests now with overwrite = true
+ FileUtil.copy(srcFile.toFile(), destFile.toFile(), null, true);
+ // make sure the copy didn't corrupt the source file
+ Assert.assertTrue("Unexpected content in source file " + srcFile, Arrays.equals(fileContent, Files.readAllBytes(srcFile)));
+ // also check the dest file has the same content as source file after the copy operation
+ Assert.assertTrue("Unexpected content in dest file " + destFile, Arrays.equals(fileContent, Files.readAllBytes(destFile)));
+ }
+
}