From 35a84fea1a9f73e54de0207a04c12f764ac8821c Mon Sep 17 00:00:00 2001 From: Gintas Grigelionis Date: Wed, 23 May 2018 06:38:49 +0200 Subject: [PATCH] Bz 22370: followlinks attribute --- manual/Types/selectors.html | 57 ++++++++++------ .../ant/types/selectors/OwnedBySelector.java | 17 ++++- .../types/selectors/PosixGroupSelector.java | 14 +++- .../selectors/PosixPermissionsSelector.java | 16 ++++- .../types/selectors/OwnedBySelectorTest.java | 45 +++++++++++-- .../selectors/PosixGroupSelectorTest.java | 33 ++++++++- .../PosixPermissionsSelectorTest.java | 67 +++++++++++++++++-- 7 files changed, 209 insertions(+), 40 deletions(-) diff --git a/manual/Types/selectors.html b/manual/Types/selectors.html index 955a1b28d..e3289af7f 100644 --- a/manual/Types/selectors.html +++ b/manual/Types/selectors.html @@ -86,7 +86,7 @@ by a given user.
  • <posixGroup>—Select files if they have a given POSIX group.
  • -
  • <posixPermissions>—Select +
  • <posixPermissions>—Select files if they have given POSIX permissions.
  • @@ -925,6 +925,11 @@ Username of the expected owner Yes + + followlinks + Must the selector follow symbolic links? + No; defaults to false (was true before Ant 1.10.4) +

    PosixGroup Selector

    @@ -937,16 +942,21 @@

    Since Ant 1.10.4

    - - - - - - - - - - + + + + + + + + + + + + + + +
    AttributeDescriptionRequired
    groupPOSIX group nameYes
    AttributeDescriptionRequired
    groupPOSIX group nameYes
    followlinksMust the selector follow symbolic links?No; defaults to false

    PosixPermissions Selector

    @@ -959,16 +969,21 @@

    Since Ant 1.10.4

    - - - - - - - - - - + + + + + + + + + + + + + + +
    AttributeDescriptionRequired
    permissionsPOSIX permissions in string (rwxrwxrwx) or octal (777) formatYes
    AttributeDescriptionRequired
    permissionsPOSIX permissions in string (rwxrwxrwx) or octal (777) formatYes
    followlinksMust the selector follow symbolic links?No; defaults to false

    Script Selector

    diff --git a/src/main/org/apache/tools/ant/types/selectors/OwnedBySelector.java b/src/main/org/apache/tools/ant/types/selectors/OwnedBySelector.java index d37fd2f64..cb21de485 100644 --- a/src/main/org/apache/tools/ant/types/selectors/OwnedBySelector.java +++ b/src/main/org/apache/tools/ant/types/selectors/OwnedBySelector.java @@ -21,9 +21,11 @@ package org.apache.tools.ant.types.selectors; import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.LinkOption; import java.nio.file.attribute.UserPrincipal; import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.PropertyHelper; /** * A selector that selects files based on their owner. @@ -40,14 +42,24 @@ public class OwnedBySelector implements FileSelector { private String owner; + private boolean followLinks = false; + /** - * Sets the User-Name to look for. + * Sets the user name to look for. * @param owner the user name */ public void setOwner(String owner) { this.owner = owner; } + /** + * Sets the "follow links" flag. + * @param followLinks the user name + */ + public void setFollowLinks(String followLinks) { + this.followLinks = PropertyHelper.toBoolean(followLinks); + } + @Override public boolean isSelected(File basedir, String filename, File file) { if (owner == null) { @@ -55,7 +67,8 @@ public class OwnedBySelector implements FileSelector { } if (file != null) { try { - UserPrincipal user = Files.getOwner(file.toPath()); + UserPrincipal user = followLinks ? Files.getOwner(file.toPath()) + : Files.getOwner(file.toPath(), LinkOption.NOFOLLOW_LINKS); return user != null && owner.equals(user.getName()); } catch (UnsupportedOperationException | IOException ex) { // => not the expected owner diff --git a/src/main/org/apache/tools/ant/types/selectors/PosixGroupSelector.java b/src/main/org/apache/tools/ant/types/selectors/PosixGroupSelector.java index 9c7498531..a72d0fd15 100644 --- a/src/main/org/apache/tools/ant/types/selectors/PosixGroupSelector.java +++ b/src/main/org/apache/tools/ant/types/selectors/PosixGroupSelector.java @@ -19,6 +19,7 @@ package org.apache.tools.ant.types.selectors; import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.PropertyHelper; import java.io.File; import java.io.IOException; @@ -41,6 +42,8 @@ public class PosixGroupSelector implements FileSelector { private String group; + private boolean followLinks = false; + /** * Sets the group name to look for. * @param group the group name @@ -49,13 +52,22 @@ public class PosixGroupSelector implements FileSelector { this.group = group; } + /** + * Sets the "follow links" flag. + * @param followLinks the user name + */ + public void setFollowLinks(String followLinks) { + this.followLinks = PropertyHelper.toBoolean(followLinks); + } + @Override public boolean isSelected(File basedir, String filename, File file) { if (group == null) { throw new BuildException("the group attribute is required"); } try { - GroupPrincipal actualGroup = Files.readAttributes(file.toPath(), + GroupPrincipal actualGroup = followLinks ? Files.readAttributes(file.toPath(), + PosixFileAttributes.class).group() : Files.readAttributes(file.toPath(), PosixFileAttributes.class, LinkOption.NOFOLLOW_LINKS).group(); return actualGroup != null && actualGroup.getName().equals(group); } catch (IOException e) { diff --git a/src/main/org/apache/tools/ant/types/selectors/PosixPermissionsSelector.java b/src/main/org/apache/tools/ant/types/selectors/PosixPermissionsSelector.java index 8cd60ab73..fd6cef71b 100644 --- a/src/main/org/apache/tools/ant/types/selectors/PosixPermissionsSelector.java +++ b/src/main/org/apache/tools/ant/types/selectors/PosixPermissionsSelector.java @@ -19,6 +19,7 @@ package org.apache.tools.ant.types.selectors; import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.PropertyHelper; import org.apache.tools.ant.util.PermissionUtils; import java.io.File; @@ -40,6 +41,8 @@ public class PosixPermissionsSelector implements FileSelector { private String permissions; + private boolean followLinks = false; + /** * Sets the permissions to look for. * @param permissions the permissions string (rwxrwxrwx or octal) @@ -59,14 +62,23 @@ public class PosixPermissionsSelector implements FileSelector { } } + /** + * Sets the "follow links" flag. + * @param followLinks the user name + */ + public void setFollowLinks(String followLinks) { + this.followLinks = PropertyHelper.toBoolean(followLinks); + } + @Override public boolean isSelected(File basedir, String filename, File file) { if (permissions == null) { throw new BuildException("the permissions attribute is required"); } try { - return PosixFilePermissions.toString( - Files.getPosixFilePermissions(file.toPath(), LinkOption.NOFOLLOW_LINKS)) + return PosixFilePermissions.toString(followLinks + ? Files.getPosixFilePermissions(file.toPath()) + : Files.getPosixFilePermissions(file.toPath(), LinkOption.NOFOLLOW_LINKS)) .equals(permissions); } catch (IOException e) { // => not the expected permissions diff --git a/src/tests/junit/org/apache/tools/ant/types/selectors/OwnedBySelectorTest.java b/src/tests/junit/org/apache/tools/ant/types/selectors/OwnedBySelectorTest.java index d73626f20..e8619e4ed 100644 --- a/src/tests/junit/org/apache/tools/ant/types/selectors/OwnedBySelectorTest.java +++ b/src/tests/junit/org/apache/tools/ant/types/selectors/OwnedBySelectorTest.java @@ -19,14 +19,19 @@ package org.apache.tools.ant.types.selectors; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; import java.io.File; +import java.io.IOException; import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; import java.nio.file.attribute.UserPrincipal; import org.apache.tools.ant.taskdefs.condition.Os; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -36,18 +41,46 @@ public class OwnedBySelectorTest { @Rule public TemporaryFolder folder = new TemporaryFolder(); - @Test - public void ownedByIsTrueForSelf() throws Exception { + private final File TEST_FILE = new File("/etc/passwd"); + + private final String SELF = System.getProperty("user.name"); + + private final String ROOT = "root"; + + private OwnedBySelector s; + + @Before + public void setUp() { // at least on Jenkins the file is owned by "BUILTIN\Administrators" assumeFalse(Os.isFamily("windows")); - String self = System.getProperty("user.name"); + + s = new OwnedBySelector(); + } + + @Test + public void ownedByIsTrueForSelf() throws Exception { File file = folder.newFile("f.txt"); UserPrincipal user = Files.getOwner(file.toPath()); - assertEquals(self, user.getName()); + assertEquals(SELF, user.getName()); - OwnedBySelector s = new OwnedBySelector(); - s.setOwner(self); + s.setOwner(SELF); assertTrue(s.isSelected(null, null, file)); } + @Test + public void ownedByFollowSymlinks() throws IOException { + File target = new File(folder.getRoot(), "link"); + Path symbolicLink = Files.createSymbolicLink(target.toPath(), TEST_FILE.toPath()); + + UserPrincipal root = Files.getOwner(symbolicLink); + assertEquals(ROOT, root.getName()); + + UserPrincipal user = Files.getOwner(symbolicLink, LinkOption.NOFOLLOW_LINKS); + assertEquals(SELF, user.getName()); + + s.setOwner(SELF); + assertTrue(s.isSelected(null, null, symbolicLink.toFile())); + s.setFollowLinks("yes"); + assertFalse(s.isSelected(null, null, symbolicLink.toFile())); + } } diff --git a/src/tests/junit/org/apache/tools/ant/types/selectors/PosixGroupSelectorTest.java b/src/tests/junit/org/apache/tools/ant/types/selectors/PosixGroupSelectorTest.java index 8d4e28ff4..2cb0a213a 100644 --- a/src/tests/junit/org/apache/tools/ant/types/selectors/PosixGroupSelectorTest.java +++ b/src/tests/junit/org/apache/tools/ant/types/selectors/PosixGroupSelectorTest.java @@ -9,10 +9,14 @@ import org.junit.rules.TemporaryFolder; import java.io.File; import java.nio.file.Files; import java.nio.file.LinkOption; +import java.nio.file.Path; import java.nio.file.attribute.GroupPrincipal; +import java.nio.file.attribute.PosixFileAttributes; import java.util.Map; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeNoException; import static org.junit.Assume.assumeTrue; @@ -24,13 +28,15 @@ public class PosixGroupSelectorTest { private final String GROUP_GETTER = "getGid"; + private final File TEST_FILE = new File("/etc/passwd"); + private Class jaasProviderClass; private PosixGroupSelector s; @Before public void setUp() { - assumeTrue(Os.isFamily("unix")); + assumeTrue("Not POSIX", Os.isFamily("unix")); String osName = System.getProperty("os.name", "unknown").toLowerCase(); String jaasProviderClassName = osName.contains("sunos") ? "com.sun.security.auth.module.SolarisSystem" @@ -46,7 +52,7 @@ public class PosixGroupSelectorTest { } @Test - public void PosixGroupIsTrueForSelf() throws Exception { + public void posixGroupIsTrueForSelf() throws Exception { long gid = (long) jaasProviderClass.getMethod(GROUP_GETTER) .invoke(jaasProviderClass.newInstance()); @@ -61,4 +67,27 @@ public class PosixGroupSelectorTest { assertTrue(s.isSelected(null, null, file)); } + @Test + public void posixGroupFollowSymlinks() throws Exception { + long gid = (long) jaasProviderClass.getMethod(GROUP_GETTER) + .invoke(jaasProviderClass.newInstance()); + + File target = new File(folder.getRoot(), "link"); + Path symbolicLink = Files.createSymbolicLink(target.toPath(), TEST_FILE.toPath()); + Map linkAttributes = Files.readAttributes(target.toPath(), + "unix:group,gid", LinkOption.NOFOLLOW_LINKS); + long linkGid = (int) linkAttributes.get("gid"); + assertEquals("Different GIDs", gid, linkGid); + + GroupPrincipal targetGroup = Files.readAttributes(target.toPath(), + PosixFileAttributes.class).group(); + GroupPrincipal linkGroup = (GroupPrincipal) linkAttributes.get("group"); + assertNotEquals("Same group name", linkGroup.getName(), + targetGroup.getName()); + + s.setGroup(linkGroup.getName()); + assertTrue(s.isSelected(null, null, symbolicLink.toFile())); + s.setFollowLinks("yes"); + assertFalse(s.isSelected(null, null, symbolicLink.toFile())); + } } diff --git a/src/tests/junit/org/apache/tools/ant/types/selectors/PosixPermissionsSelectorTest.java b/src/tests/junit/org/apache/tools/ant/types/selectors/PosixPermissionsSelectorTest.java index c72b61ae6..1dde9c482 100644 --- a/src/tests/junit/org/apache/tools/ant/types/selectors/PosixPermissionsSelectorTest.java +++ b/src/tests/junit/org/apache/tools/ant/types/selectors/PosixPermissionsSelectorTest.java @@ -10,9 +10,16 @@ import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermission; import java.util.Arrays; import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; @@ -35,7 +42,7 @@ public class PosixPermissionsSelectorTest { @Before public void setUp() { - assumeTrue("no POSIX", Os.isFamily("unix")); + assumeTrue("Not POSIX", Os.isFamily("unix")); s = new PosixPermissionsSelector(); } @@ -54,9 +61,9 @@ public class PosixPermissionsSelectorTest { public TemporaryFolder folder = new TemporaryFolder(); // requires JUnit 4.12 - @Parameterized.Parameters(name = "legal argument: |{0}|") + @Parameterized.Parameters(name = "legal argument (self): |{0}|") public static Collection data() { - return Arrays.asList("755", "rwxr-xr-x"); + return Arrays.asList("750", "rwxr-x---"); } @Parameterized.Parameter @@ -64,14 +71,62 @@ public class PosixPermissionsSelectorTest { @Before public void setUp() { - assumeTrue("No POSIX", Os.isFamily("unix")); + assumeTrue("Not POSIX", Os.isFamily("unix")); s = new PosixPermissionsSelector(); } @Test - public void PosixPermissionsIsTrueForSelf() throws Exception { + public void test() throws Exception { + // do not depend on default umask + File subFolder = folder.newFolder(); + Set permissions = new HashSet<>(); + permissions.add(PosixFilePermission.OWNER_READ); + permissions.add(PosixFilePermission.OWNER_WRITE); + permissions.add(PosixFilePermission.OWNER_EXECUTE); + permissions.add(PosixFilePermission.GROUP_READ); + permissions.add(PosixFilePermission.GROUP_EXECUTE); + Files.setPosixFilePermissions(subFolder.toPath(), permissions); + + s.setPermissions(argument); + assertTrue(s.isSelected(null, null, subFolder)); + } + } + + @RunWith(Parameterized.class) + public static class LegalSymbolicLinkArgumentTest { + + private final File TEST_FILE = new File("/etc/passwd"); + + private PosixPermissionsSelector s; + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + // requires JUnit 4.12 + @Parameterized.Parameters(name = "legal argument (link): |{0}|") + public static Collection data() { + return Arrays.asList("644", "rw-r--r--"); + } + + @Parameterized.Parameter + public String argument; + + @Before + public void setUp() { + assumeTrue("Not POSIX", Os.isFamily("unix")); + s = new PosixPermissionsSelector(); + } + + @Test + public void test() throws Exception { + // symlinks have execute bit set by default + File target = new File(folder.getRoot(), "link"); + Path symbolicLink = Files.createSymbolicLink(target.toPath(), TEST_FILE.toPath()); + s.setPermissions(argument); - assertTrue(s.isSelected(null, null, folder.newFolder())); + assertFalse(s.isSelected(null, null, symbolicLink.toFile())); + s.setFollowLinks("yes"); + assertTrue(s.isSelected(null, null, symbolicLink.toFile())); } }