diff --git a/manual/Types/selectors.html b/manual/Types/selectors.html index f12e2da26..955a1b28d 100644 --- a/manual/Types/selectors.html +++ b/manual/Types/selectors.html @@ -84,6 +84,10 @@ symlinks.
  • <ownedBy>—Select files if they are owned by a given user.
  • +
  • <posixGroup>—Select + files if they have a given POSIX group.
  • +
  • <posixPermissions>—Select + files if they have given POSIX permissions.
  • Contains Selector

    @@ -923,6 +927,50 @@ +

    PosixGroup Selector

    + +

    The <posixGroup> selector selects only files that are owned by the given + POSIX group. Ant only invokes java.nio.file.Files#readAttributes so + if a file system doesn't support the operation or POSIX attributes this selector will not + select the file.

    + +

    Since Ant 1.10.4

    + + + + + + + + + + + + +
    AttributeDescriptionRequired
    groupPOSIX group nameYes
    + +

    PosixPermissions Selector

    + +

    The <posixPermissions> selector selects only files that have the given + POSIX permissions. Ant only + invokes java.nio.file.Files#getPosixFilePermissions so if a file + system doesn't support the operation this selector will not select the file.

    + +

    Since Ant 1.10.4

    + + + + + + + + + + + + +
    AttributeDescriptionRequired
    permissionsPOSIX permissions in string (rwxrwxrwx) or octal (777) formatYes
    +

    Script Selector

    The <scriptselector> element enables you to write a complex selection diff --git a/src/main/org/apache/tools/ant/types/AbstractFileSet.java b/src/main/org/apache/tools/ant/types/AbstractFileSet.java index 7c0651af9..482fef4e4 100644 --- a/src/main/org/apache/tools/ant/types/AbstractFileSet.java +++ b/src/main/org/apache/tools/ant/types/AbstractFileSet.java @@ -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.OrSelector; 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.ReadableSelector; import org.apache.tools.ant.types.selectors.SelectSelector; @@ -824,7 +826,7 @@ public abstract class AbstractFileSet extends DataType /** * Add the modified selector. * @param selector the ModifiedSelector to add. - * @since ant 1.6 + * @since Ant 1.6 */ @Override public void addModified(ModifiedSelector selector) { @@ -863,6 +865,22 @@ public abstract class AbstractFileSet extends DataType 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. * @param selector the FileSelector to add. diff --git a/src/main/org/apache/tools/ant/types/selectors/AbstractSelectorContainer.java b/src/main/org/apache/tools/ant/types/selectors/AbstractSelectorContainer.java index 27fa1577c..f8f9b1906 100644 --- a/src/main/org/apache/tools/ant/types/selectors/AbstractSelectorContainer.java +++ b/src/main/org/apache/tools/ant/types/selectors/AbstractSelectorContainer.java @@ -324,6 +324,22 @@ public abstract class AbstractSelectorContainer extends DataType 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 * @param selector the selector to add diff --git a/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java b/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java index fe90b3863..7703ea64f 100644 --- a/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java +++ b/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java @@ -320,6 +320,22 @@ public abstract class BaseSelectorContainer extends BaseSelector 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 * @param selector the selector to add diff --git a/src/main/org/apache/tools/ant/types/selectors/PosixGroupSelector.java b/src/main/org/apache/tools/ant/types/selectors/PosixGroupSelector.java new file mode 100644 index 000000000..9c7498531 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/PosixGroupSelector.java @@ -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. + * + *

    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.

    + * + * @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; + } +} diff --git a/src/main/org/apache/tools/ant/types/selectors/PosixPermissionsSelector.java b/src/main/org/apache/tools/ant/types/selectors/PosixPermissionsSelector.java new file mode 100644 index 000000000..8cd60ab73 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/PosixPermissionsSelector.java @@ -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. + * + *

    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.

    + * + * @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; + } +} 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 new file mode 100644 index 000000000..8d4e28ff4 --- /dev/null +++ b/src/tests/junit/org/apache/tools/ant/types/selectors/PosixGroupSelectorTest.java @@ -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 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)); + } + +} 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 new file mode 100644 index 000000000..c72b61ae6 --- /dev/null +++ b/src/tests/junit/org/apache/tools/ant/types/selectors/PosixPermissionsSelectorTest.java @@ -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 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 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())); + } + } + +}