@@ -84,6 +84,10 @@ | |||||
symlinks.</li> | symlinks.</li> | ||||
<li><a href="#ownedBy"><code><ownedBy></code></a>—Select files if they are owned | <li><a href="#ownedBy"><code><ownedBy></code></a>—Select files if they are owned | ||||
by a given user.</li> | 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 | |||||
files if they have given POSIX permissions.</li> | |||||
</ul> | </ul> | ||||
<h4 id="containsselect">Contains Selector</h4> | <h4 id="containsselect">Contains Selector</h4> | ||||
@@ -923,6 +927,50 @@ | |||||
</tr> | </tr> | ||||
</table> | </table> | ||||
<h4 id="posixGroup">PosixGroup Selector</h4> | |||||
<p>The <code><posixGroup></code> selector selects only files that are owned by the given | |||||
POSIX group. Ant only invokes <code class="code">java.nio.file.Files#readAttributes</code> so | |||||
if a file system doesn't support the operation or POSIX attributes this selector will not | |||||
select the file.</p> | |||||
<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> | |||||
</table> | |||||
<h4 id="posixPermissions">PosixPermissions Selector</h4> | |||||
<p>The <code><posixPermissions></code> selector selects only files that have the given | |||||
POSIX permissions. Ant only | |||||
invokes <code class="code">java.nio.file.Files#getPosixFilePermissions</code> so if a file | |||||
system doesn't support the operation this selector will not select the file.</p> | |||||
<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> | |||||
</table> | |||||
<h4 id="scriptselector">Script Selector</h4> | <h4 id="scriptselector">Script Selector</h4> | ||||
<p>The <code><scriptselector></code> element enables you to write a complex selection | <p>The <code><scriptselector></code> element enables you to write a complex selection | ||||
@@ -46,6 +46,8 @@ import org.apache.tools.ant.types.selectors.NoneSelector; | |||||
import org.apache.tools.ant.types.selectors.NotSelector; | import org.apache.tools.ant.types.selectors.NotSelector; | ||||
import org.apache.tools.ant.types.selectors.OrSelector; | import org.apache.tools.ant.types.selectors.OrSelector; | ||||
import org.apache.tools.ant.types.selectors.OwnedBySelector; | import org.apache.tools.ant.types.selectors.OwnedBySelector; | ||||
import org.apache.tools.ant.types.selectors.PosixGroupSelector; | |||||
import org.apache.tools.ant.types.selectors.PosixPermissionsSelector; | |||||
import org.apache.tools.ant.types.selectors.PresentSelector; | import org.apache.tools.ant.types.selectors.PresentSelector; | ||||
import org.apache.tools.ant.types.selectors.ReadableSelector; | import org.apache.tools.ant.types.selectors.ReadableSelector; | ||||
import org.apache.tools.ant.types.selectors.SelectSelector; | import org.apache.tools.ant.types.selectors.SelectSelector; | ||||
@@ -824,7 +826,7 @@ public abstract class AbstractFileSet extends DataType | |||||
/** | /** | ||||
* Add the modified selector. | * Add the modified selector. | ||||
* @param selector the <code>ModifiedSelector</code> to add. | * @param selector the <code>ModifiedSelector</code> to add. | ||||
* @since ant 1.6 | |||||
* @since Ant 1.6 | |||||
*/ | */ | ||||
@Override | @Override | ||||
public void addModified(ModifiedSelector selector) { | public void addModified(ModifiedSelector selector) { | ||||
@@ -863,6 +865,22 @@ public abstract class AbstractFileSet extends DataType | |||||
appendSelector(o); | appendSelector(o); | ||||
} | } | ||||
/** | |||||
* @param o PosixGroupSelector | |||||
* @since 1.10.4 | |||||
*/ | |||||
public void addPosixGroup(PosixGroupSelector o) { | |||||
appendSelector(o); | |||||
} | |||||
/** | |||||
* @param o PosixPermissionsSelector | |||||
* @since 1.10.4 | |||||
*/ | |||||
public void addPosixPermissions(PosixPermissionsSelector o) { | |||||
appendSelector(o); | |||||
} | |||||
/** | /** | ||||
* Add an arbitrary selector. | * Add an arbitrary selector. | ||||
* @param selector the <code>FileSelector</code> to add. | * @param selector the <code>FileSelector</code> to add. | ||||
@@ -324,6 +324,22 @@ public abstract class AbstractSelectorContainer extends DataType | |||||
appendSelector(o); | appendSelector(o); | ||||
} | } | ||||
/** | |||||
* @param o PosixGroupSelector | |||||
* @since 1.10.4 | |||||
*/ | |||||
public void addPosixGroup(PosixGroupSelector o) { | |||||
appendSelector(o); | |||||
} | |||||
/** | |||||
* @param o PosixPermissionsSelector | |||||
* @since 1.10.4 | |||||
*/ | |||||
public void addPosixPermissions(PosixPermissionsSelector o) { | |||||
appendSelector(o); | |||||
} | |||||
/** | /** | ||||
* add an arbitrary selector | * add an arbitrary selector | ||||
* @param selector the selector to add | * @param selector the selector to add | ||||
@@ -320,6 +320,22 @@ public abstract class BaseSelectorContainer extends BaseSelector | |||||
appendSelector(o); | appendSelector(o); | ||||
} | } | ||||
/** | |||||
* @param o PosixGroupSelector | |||||
* @since 1.10.4 | |||||
*/ | |||||
public void addPosixGroup(PosixGroupSelector o) { | |||||
appendSelector(o); | |||||
} | |||||
/** | |||||
* @param o PosixPermissionsSelector | |||||
* @since 1.10.4 | |||||
*/ | |||||
public void addPosixPermissions(PosixPermissionsSelector o) { | |||||
appendSelector(o); | |||||
} | |||||
/** | /** | ||||
* add an arbitrary selector | * add an arbitrary selector | ||||
* @param selector the selector to add | * @param selector the selector to add | ||||
@@ -0,0 +1,66 @@ | |||||
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
* (the "License"); you may not use this file except in compliance with | |||||
* the License. You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
* | |||||
*/ | |||||
package org.apache.tools.ant.types.selectors; | |||||
import org.apache.tools.ant.BuildException; | |||||
import java.io.File; | |||||
import java.io.IOException; | |||||
import java.nio.file.Files; | |||||
import java.nio.file.LinkOption; | |||||
import java.nio.file.attribute.GroupPrincipal; | |||||
import java.nio.file.attribute.PosixFileAttributes; | |||||
/** | |||||
* A selector that selects files based on their POSIX group. | |||||
* | |||||
* <p>Group is defined in terms of {@link java.nio.file.Files#readAttributes} | |||||
* group attribute as provided by {@link java.nio.file.attribute.PosixFileAttributes}, | |||||
* this means the selector will accept any file that exists and has the given | |||||
* group attribute.</p> | |||||
* | |||||
* @since Ant 1.10.4 | |||||
*/ | |||||
public class PosixGroupSelector implements FileSelector { | |||||
private String group; | |||||
/** | |||||
* Sets the group name to look for. | |||||
* @param group the group name | |||||
*/ | |||||
public void setGroup(String group) { | |||||
this.group = group; | |||||
} | |||||
@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(), | |||||
PosixFileAttributes.class, LinkOption.NOFOLLOW_LINKS).group(); | |||||
return actualGroup != null && actualGroup.getName().equals(group); | |||||
} catch (IOException e) { | |||||
// => not the expected group | |||||
} | |||||
return false; | |||||
} | |||||
} |
@@ -0,0 +1,76 @@ | |||||
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
* (the "License"); you may not use this file except in compliance with | |||||
* the License. You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
* | |||||
*/ | |||||
package org.apache.tools.ant.types.selectors; | |||||
import org.apache.tools.ant.BuildException; | |||||
import org.apache.tools.ant.util.PermissionUtils; | |||||
import java.io.File; | |||||
import java.io.IOException; | |||||
import java.nio.file.Files; | |||||
import java.nio.file.LinkOption; | |||||
import java.nio.file.attribute.PosixFilePermissions; | |||||
/** | |||||
* A selector that selects files based on their POSIX permissions. | |||||
* | |||||
* <p>Permissions are defined in terms of {@link | |||||
* java.nio.file.Files#getPosixFilePermissions}, this means the selector will accept | |||||
* any file that exists and has given POSIX permissions.</p> | |||||
* | |||||
* @since Ant 1.10.4 | |||||
*/ | |||||
public class PosixPermissionsSelector implements FileSelector { | |||||
private String permissions; | |||||
/** | |||||
* Sets the permissions to look for. | |||||
* @param permissions the permissions string (rwxrwxrwx or octal) | |||||
*/ | |||||
public void setPermissions(String permissions) { | |||||
if (permissions.length() == 3 && permissions.matches("^[0-7]+$")) { | |||||
this.permissions = PosixFilePermissions.toString( | |||||
PermissionUtils.permissionsFromMode(Integer.parseInt(permissions, 8))); | |||||
return; | |||||
} | |||||
try { | |||||
this.permissions = PosixFilePermissions.toString(PosixFilePermissions.fromString(permissions)); | |||||
} catch (IllegalArgumentException ex) { | |||||
throw new BuildException("the permissions attribute " + permissions | |||||
+ " is invalid", ex); | |||||
} | |||||
} | |||||
@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)) | |||||
.equals(permissions); | |||||
} catch (IOException e) { | |||||
// => not the expected permissions | |||||
} | |||||
return false; | |||||
} | |||||
} |
@@ -0,0 +1,64 @@ | |||||
package org.apache.tools.ant.types.selectors; | |||||
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; | |||||
import java.io.File; | |||||
import java.nio.file.Files; | |||||
import java.nio.file.LinkOption; | |||||
import java.nio.file.attribute.GroupPrincipal; | |||||
import java.util.Map; | |||||
import static org.junit.Assert.assertEquals; | |||||
import static org.junit.Assert.assertTrue; | |||||
import static org.junit.Assume.assumeNoException; | |||||
import static org.junit.Assume.assumeTrue; | |||||
public class PosixGroupSelectorTest { | |||||
@Rule | |||||
public TemporaryFolder folder = new TemporaryFolder(); | |||||
private final String GROUP_GETTER = "getGid"; | |||||
private Class<?> jaasProviderClass; | |||||
private PosixGroupSelector s; | |||||
@Before | |||||
public void setUp() { | |||||
assumeTrue(Os.isFamily("unix")); | |||||
String osName = System.getProperty("os.name", "unknown").toLowerCase(); | |||||
String jaasProviderClassName = osName.contains("sunos") | |||||
? "com.sun.security.auth.module.SolarisSystem" | |||||
: "com.sun.security.auth.module.UnixSystem"; | |||||
try { | |||||
jaasProviderClass = Class.forName(jaasProviderClassName); | |||||
} catch (Throwable e) { | |||||
assumeNoException("Cannot obtain OS-specific JAAS information", e); | |||||
} | |||||
s = new PosixGroupSelector(); | |||||
} | |||||
@Test | |||||
public void PosixGroupIsTrueForSelf() throws Exception { | |||||
long gid = (long) jaasProviderClass.getMethod(GROUP_GETTER) | |||||
.invoke(jaasProviderClass.newInstance()); | |||||
File file = folder.newFile("f.txt"); | |||||
Map<String, Object> fileAttributes = Files.readAttributes(file.toPath(), | |||||
"unix:group,gid", LinkOption.NOFOLLOW_LINKS); | |||||
long actualGid = (int) fileAttributes.get("gid"); | |||||
assertEquals("Different GIDs", gid, actualGid); | |||||
GroupPrincipal actualGroup = (GroupPrincipal) fileAttributes.get("group"); | |||||
s.setGroup(actualGroup.getName()); | |||||
assertTrue(s.isSelected(null, null, file)); | |||||
} | |||||
} |
@@ -0,0 +1,78 @@ | |||||
package org.apache.tools.ant.types.selectors; | |||||
import org.apache.tools.ant.BuildException; | |||||
import org.apache.tools.ant.taskdefs.condition.Os; | |||||
import org.junit.Before; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.junit.experimental.runners.Enclosed; | |||||
import org.junit.rules.TemporaryFolder; | |||||
import org.junit.runner.RunWith; | |||||
import org.junit.runners.Parameterized; | |||||
import java.util.Arrays; | |||||
import java.util.Collection; | |||||
import static org.junit.Assert.assertTrue; | |||||
import static org.junit.Assume.assumeTrue; | |||||
@RunWith(Enclosed.class) | |||||
public class PosixPermissionsSelectorTest { | |||||
@RunWith(Parameterized.class) | |||||
public static class IllegalArgumentTest { | |||||
private PosixPermissionsSelector s; | |||||
// requires JUnit 4.12 | |||||
@Parameterized.Parameters(name = "illegal argument: |{0}|") | |||||
public static Collection<String> data() { | |||||
return Arrays.asList("855", "4555", "-rwxr-xr-x", "xrwr-xr-x"); | |||||
} | |||||
@Parameterized.Parameter | |||||
public String argument; | |||||
@Before | |||||
public void setUp() { | |||||
assumeTrue("no POSIX", Os.isFamily("unix")); | |||||
s = new PosixPermissionsSelector(); | |||||
} | |||||
@Test(expected = BuildException.class) | |||||
public void test() { | |||||
s.setPermissions(argument); | |||||
} | |||||
} | |||||
@RunWith(Parameterized.class) | |||||
public static class LegalArgumentTest { | |||||
private PosixPermissionsSelector s; | |||||
@Rule | |||||
public TemporaryFolder folder = new TemporaryFolder(); | |||||
// requires JUnit 4.12 | |||||
@Parameterized.Parameters(name = "legal argument: |{0}|") | |||||
public static Collection<String> data() { | |||||
return Arrays.asList("755", "rwxr-xr-x"); | |||||
} | |||||
@Parameterized.Parameter | |||||
public String argument; | |||||
@Before | |||||
public void setUp() { | |||||
assumeTrue("No POSIX", Os.isFamily("unix")); | |||||
s = new PosixPermissionsSelector(); | |||||
} | |||||
@Test | |||||
public void PosixPermissionsIsTrueForSelf() throws Exception { | |||||
s.setPermissions(argument); | |||||
assertTrue(s.isSelected(null, null, folder.newFolder())); | |||||
} | |||||
} | |||||
} |