| @@ -86,7 +86,7 @@ | |||
| by a given user.</li> | |||
| <li><a href="#posixGroup"><code><posixGroup></code>—Select | |||
| files if they have a given POSIX group.</li> | |||
| <li><a href="#posixPermissions"><code><posixPermissions></code>—Select | |||
| <li><a href="#posixPermissions"><code><posixPermissions></code></a>—Select | |||
| files if they have given POSIX permissions.</li> | |||
| </ul> | |||
| @@ -925,6 +925,11 @@ | |||
| <td>Username of the expected owner</td> | |||
| <td>Yes</td> | |||
| </tr> | |||
| <tr> | |||
| <td>followlinks</td> | |||
| <td>Must the selector follow symbolic links?</td> | |||
| <td>No; defaults to <q>false</q> (was <q>true</q> before Ant 1.10.4)</td> | |||
| </tr> | |||
| </table> | |||
| <h4 id="posixGroup">PosixGroup Selector</h4> | |||
| @@ -937,16 +942,21 @@ | |||
| <p><em>Since Ant 1.10.4</em></p> | |||
| <table class="attr"> | |||
| <tr> | |||
| <th scope="col">Attribute</th> | |||
| <th scope="col">Description</th> | |||
| <th scope="col">Required</th> | |||
| </tr> | |||
| <tr> | |||
| <td>group</td> | |||
| <td>POSIX group name</td> | |||
| <td>Yes</td> | |||
| </tr> | |||
| <tr> | |||
| <th scope="col">Attribute</th> | |||
| <th scope="col">Description</th> | |||
| <th scope="col">Required</th> | |||
| </tr> | |||
| <tr> | |||
| <td>group</td> | |||
| <td>POSIX group name</td> | |||
| <td>Yes</td> | |||
| </tr> | |||
| <tr> | |||
| <td>followlinks</td> | |||
| <td>Must the selector follow symbolic links?</td> | |||
| <td>No; defaults to <q>false</q></td> | |||
| </tr> | |||
| </table> | |||
| <h4 id="posixPermissions">PosixPermissions Selector</h4> | |||
| @@ -959,16 +969,21 @@ | |||
| <p><em>Since Ant 1.10.4</em></p> | |||
| <table class="attr"> | |||
| <tr> | |||
| <th scope="col">Attribute</th> | |||
| <th scope="col">Description</th> | |||
| <th scope="col">Required</th> | |||
| </tr> | |||
| <tr> | |||
| <td>permissions</td> | |||
| <td>POSIX permissions in string (<q>rwxrwxrwx</q>) or octal (<q>777</q>) format</td> | |||
| <td>Yes</td> | |||
| </tr> | |||
| <tr> | |||
| <th scope="col">Attribute</th> | |||
| <th scope="col">Description</th> | |||
| <th scope="col">Required</th> | |||
| </tr> | |||
| <tr> | |||
| <td>permissions</td> | |||
| <td>POSIX permissions in string (<q>rwxrwxrwx</q>) or octal (<q>777</q>) format</td> | |||
| <td>Yes</td> | |||
| </tr> | |||
| <tr> | |||
| <td>followlinks</td> | |||
| <td>Must the selector follow symbolic links?</td> | |||
| <td>No; defaults to <q>false</q></td> | |||
| </tr> | |||
| </table> | |||
| <h4 id="scriptselector">Script Selector</h4> | |||
| @@ -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 | |||
| @@ -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) { | |||
| @@ -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 | |||
| @@ -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())); | |||
| } | |||
| } | |||
| @@ -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<String, Object> 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())); | |||
| } | |||
| } | |||
| @@ -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<String> 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<PosixFilePermission> 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<String> 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())); | |||
| } | |||
| } | |||