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