@@ -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())); | |||
} | |||
} | |||