From 6a41d62cb9ab4e640b72cb4de42a6c211dea645d Mon Sep 17 00:00:00 2001 From: Stefan Bodewig Date: Sun, 1 Jul 2018 11:03:01 +0200 Subject: [PATCH] add additional isLeadingPath method that resolves symlinks --- .../org/apache/tools/ant/util/FileUtils.java | 30 ++++++++++++++++++ .../apache/tools/ant/util/FileUtilsTest.java | 31 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/main/org/apache/tools/ant/util/FileUtils.java b/src/main/org/apache/tools/ant/util/FileUtils.java index 1f3aba51d..900b65b51 100644 --- a/src/main/org/apache/tools/ant/util/FileUtils.java +++ b/src/main/org/apache/tools/ant/util/FileUtils.java @@ -1210,6 +1210,36 @@ public class FileUtils { return p.startsWith(l); } + /** + * Learn whether one path "leads" another. + * + * @param leading The leading path, must not be null, must be absolute. + * @param path The path to check, must not be null, must be absolute. + * @param resolveSymlinks whether symbolic links shall be resolved + * prior to comparing the paths. + * @return true if path starts with leading; false otherwise. + * @since Ant 1.9.13 + * @throws IOException if resolveSymlinks is true and invoking + * getCanonicaPath on either argument throws an exception + */ + public boolean isLeadingPath(File leading, File path, boolean resolveSymlinks) + throws IOException { + if (!resolveSymlinks) { + return isLeadingPath(leading, path); + } + String l = leading.getCanonicalPath(); + String p = path.getCanonicalPath(); + if (l.equals(p)) { + return true; + } + // ensure that l ends with a / + // so we never think /foo was a parent directory of /foobar + if (!l.endsWith(File.separator)) { + l += File.separator; + } + return p.startsWith(l); + } + /** * Constructs a file: URI that represents the * external form of the given pathname. diff --git a/src/tests/junit/org/apache/tools/ant/util/FileUtilsTest.java b/src/tests/junit/org/apache/tools/ant/util/FileUtilsTest.java index fef72716f..716751d4d 100644 --- a/src/tests/junit/org/apache/tools/ant/util/FileUtilsTest.java +++ b/src/tests/junit/org/apache/tools/ant/util/FileUtilsTest.java @@ -32,6 +32,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; /** @@ -603,6 +604,36 @@ public class FileUtilsTest { assertFalse(FILE_UTILS.isLeadingPath(new File("/foo"), new File("/foo/../.."))); } + /** + * @see "https://bz.apache.org/bugzilla/show_bug.cgi?id=62502" + */ + @Test + public void isLeadingPathCanonicalVersionCannotBeFooledByTooManyDoubleDots() throws IOException { + assertFalse(FILE_UTILS.isLeadingPath(new File("/foo"), new File("/foo/../../bar"), true)); + assertFalse(FILE_UTILS.isLeadingPath(new File("c:\\foo"), new File("c:\\foo\\..\\..\\bar"), true)); + assertFalse(FILE_UTILS.isLeadingPath(new File("/foo"), new File("/foo/../.."), true)); + } + + @Test + public void isLeadingPathCanonicalVersionWorksAsExpectedOnUnix() throws IOException { + assumeFalse("Test doesn't run on DOS", Os.isFamily("dos")); + assertTrue(FILE_UTILS.isLeadingPath(new File("/foo"), new File("/foo/bar"), true)); + assertTrue(FILE_UTILS.isLeadingPath(new File("/foo"), new File("/foo/baz/../bar"), true)); + assertTrue(FILE_UTILS.isLeadingPath(new File("/foo"), new File("/foo/../foo/bar"), true)); + assertFalse(FILE_UTILS.isLeadingPath(new File("/foo"), new File("/foobar"), true)); + assertFalse(FILE_UTILS.isLeadingPath(new File("/foo"), new File("/bar"), true)); + } + + @Test + public void isLeadingPathCanonicalVersionWorksAsExpectedOnDos() throws IOException { + assumeTrue("Test only runs on DOS", Os.isFamily("dos")); + assertTrue(FILE_UTILS.isLeadingPath(new File("C:\\foo"), new File("C:\\foo\\bar"), true)); + assertTrue(FILE_UTILS.isLeadingPath(new File("C:\\foo"), new File("C:\\foo\\baz\\..\\bar"), true)); + assertTrue(FILE_UTILS.isLeadingPath(new File("C:\\foo"), new File("C:\\foo\\..\\foo\\bar"), true)); + assertFalse(FILE_UTILS.isLeadingPath(new File("C:\\foo"), new File("C:\\foobar"), true)); + assertFalse(FILE_UTILS.isLeadingPath(new File("C:\\foo"), new File("C:\\bar"), true)); + } + /** * adapt file separators to local conventions */