This is an automated email from the ASF dual-hosted git repository. bodewig pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/ant.git
commit e60943e10cb4e9c08b9fae8dc0d23b594d6f80ae Author: Stefan Bodewig <[email protected]> AuthorDate: Sun Feb 8 11:38:08 2026 +0100 allow permissions to be set on links themselves rather their targets --- WHATSNEW | 5 ++ manual/Tasks/setpermissions.html | 7 ++ .../apache/tools/ant/taskdefs/SetPermissions.java | 22 +++++- .../org/apache/tools/ant/util/PermissionUtils.java | 82 ++++++++++++++++++++-- 4 files changed, 109 insertions(+), 7 deletions(-) diff --git a/WHATSNEW b/WHATSNEW index dfd580f62..dfc5fa1cb 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -82,6 +82,11 @@ Other changes: * added <windowsjunction> file selector which only select directories that are Windows junctions. + * added a new actOnLinkTargets attribute to <setpermissions> to + control whether the permissions apply to a symbolic link or Windows + junction or the target of the respective links. The old behavior + of changing the link's target remains as default. + Changes from Ant 1.10.14 TO Ant 1.10.15 ======================================= diff --git a/manual/Tasks/setpermissions.html b/manual/Tasks/setpermissions.html index f6ac15ef2..0805c372e 100644 --- a/manual/Tasks/setpermissions.html +++ b/manual/Tasks/setpermissions.html @@ -73,6 +73,13 @@ <h3>Parameters</h3> <td>Whether to stop the build if setting permissions fails.</td> <td>No; defaults to <q>true</q></td> </tr> + <tr> + <td>actOnLinkTargets</td> + <td>Whether to set the permissions of the targets of symbolic + links or Windows junctions instead of the links + themselves. <em>since Ant 1.10.16</em>.</td> + <td>No; defaults to <q>true</q></td> + </tr> </table> <h3>Parameters specified as nested elements</h3> diff --git a/src/main/org/apache/tools/ant/taskdefs/SetPermissions.java b/src/main/org/apache/tools/ant/taskdefs/SetPermissions.java index 3e708f442..269c94c1e 100644 --- a/src/main/org/apache/tools/ant/taskdefs/SetPermissions.java +++ b/src/main/org/apache/tools/ant/taskdefs/SetPermissions.java @@ -20,6 +20,7 @@ package org.apache.tools.ant.taskdefs; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.attribute.DosFileAttributeView; import java.nio.file.attribute.PosixFilePermission; @@ -56,6 +57,7 @@ public class SetPermissions extends Task { EnumSet.noneOf(PosixFilePermission.class); private Resources resources = null; private boolean failonerror = true; + private boolean actOnLinkTargets = true; private NonPosixMode nonPosixMode = NonPosixMode.fail; /** @@ -126,6 +128,19 @@ public class SetPermissions extends Task { this.nonPosixMode = m; } + /** + * Sets whether permissions should be applied to symbolic links or + * Windows junctions themselves or the link's targets. + * + * <p>The default value is {@code true}.</p> + * + * @param actOnLinkTargets true if permissions of link targets should be set. + * @since Ant 1.10.16 + */ + public void setActOnLinkTarget(boolean actOnLinkTargets) { + this.actOnLinkTargets = actOnLinkTargets; + } + /** * Adds a collection of resources to set permissions on. * @param rc a resource collection @@ -147,7 +162,8 @@ public class SetPermissions extends Task { for (Resource r : resources) { currentResource = r; try { - PermissionUtils.setPermissions(r, permissions, this::posixPermissionsNotSupported); + PermissionUtils.setPermissions(r, permissions, actOnLinkTargets, + this::posixPermissionsNotSupported); } catch (IOException ioe) { maybeThrowException(ioe, "Failed to set permissions on '%s' due to %s", r, ioe.getMessage()); } @@ -199,7 +215,9 @@ public class SetPermissions extends Task { private void tryDos(Path p, boolean failIfDosIsNotSupported) { log("Falling back to DosFileAttributeView", Project.MSG_DEBUG); boolean readOnly = !isWritable(); - DosFileAttributeView view = Files.getFileAttributeView(p, DosFileAttributeView.class); + DosFileAttributeView view = actOnLinkTargets + ? Files.getFileAttributeView(p, DosFileAttributeView.class) + : Files.getFileAttributeView(p, DosFileAttributeView.class, LinkOption.NOFOLLOW_LINKS); if (view != null) { try { view.setReadOnly(readOnly); diff --git a/src/main/org/apache/tools/ant/util/PermissionUtils.java b/src/main/org/apache/tools/ant/util/PermissionUtils.java index b32e410e7..fba630cc2 100644 --- a/src/main/org/apache/tools/ant/util/PermissionUtils.java +++ b/src/main/org/apache/tools/ant/util/PermissionUtils.java @@ -103,6 +103,10 @@ public class PermissionUtils { * <li>{@link ArchiveResource}</li> * </ul> * + * <p>When applied to a {@code FileProvider} providing a symbolic + * link or Windows junction, the permission of the link target are + * set, not the permssions of the link itself.</p> + * * @param r the resource to set permissions for * @param permissions the permissions * @param posixNotSupportedCallback optional callback that is @@ -114,11 +118,42 @@ public class PermissionUtils { public static void setPermissions(Resource r, Set<PosixFilePermission> permissions, Consumer<Path> posixNotSupportedCallback) throws IOException { + setPermissions(r, permissions, true, posixNotSupportedCallback); + } + + /** + * Sets permissions on a {@link Resource} - doesn't do anything + * for unsupported resource types. + * + * <p>Supported types are:</p> + * <ul> + * <li>any {@link FileProvider}</li> + * <li>{@link ArchiveResource}</li> + * </ul> + * + * @param r the resource to set permissions for + * @param permissions the permissions + * @param actOnLinkTarget whether to set the permissions on a + * symbolic link or Windows junction itself instead of the link's + * target. Only applies to resources that are {@code + * FileProvider}s. + * @param posixNotSupportedCallback optional callback that is + * invoked for a file provider resource if the file-system holding + * the file doesn't support PosixFilePermissions. The Path + * corresponding to the file is passed to the callback. + * @throws IOException if something goes wrong + * @since Ant 1.10.16 + */ + public static void setPermissions(Resource r, Set<PosixFilePermission> permissions, + boolean actOnLinkTarget, + Consumer<Path> posixNotSupportedCallback) + throws IOException { FileProvider f = r.as(FileProvider.class); if (f != null) { Path p = f.getFile().toPath(); - PosixFileAttributeView view = - Files.getFileAttributeView(p, PosixFileAttributeView.class); + PosixFileAttributeView view = actOnLinkTarget + ? Files.getFileAttributeView(p, PosixFileAttributeView.class) + : Files.getFileAttributeView(p, PosixFileAttributeView.class, LinkOption.NOFOLLOW_LINKS); if (view != null) { view.setPermissions(permissions); } else if (posixNotSupportedCallback != null) { @@ -131,7 +166,37 @@ public class PermissionUtils { } /** - * Sets permissions of a {@link Resource} - returns an empty set + * Reads permissions of a {@link Resource} - returns an empty set + * for unsupported resource types or file systems that don't + * support PosixFilePermissions and no fallback has been + * provided.. + * + * <p>Supported types are:</p> + * <ul> + * <li>any {@link FileProvider}</li> + * <li>{@link ArchiveResource}</li> + * </ul> + * + * <p>When applied to a {@code FileProvider} providing a symbolic + * link or Windows junction, the permission of the link target are + * read, not the permssions of the link itself.</p> + * + * @param r the resource to read permissions from + * @param posixNotSupportedFallback optional fallback function to provide + * permissions for file system that don't support + * PosixFilePermissions. The Path corresponding to the file is + * passed to the callback. + * @return the permissions + * @throws IOException if something goes wrong + */ + public static Set<PosixFilePermission> getPermissions(Resource r, + Function<Path, Set<PosixFilePermission>> posixNotSupportedFallback) + throws IOException { + return getPermissions(r, true, posixNotSupportedFallback); + } + + /** + * Reads permissions of a {@link Resource} - returns an empty set * for unsupported resource types or file systems that don't * support PosixFilePermissions and no fallback has been * provided.. @@ -143,21 +208,28 @@ public class PermissionUtils { * </ul> * * @param r the resource to read permissions from + * @param readFromLinkTarget whether to read the permissions of a + * symbolic link or Windows junction itself instead of the link's + * target. Only applies to resources that are {@code + * FileProvider}s. * @param posixNotSupportedFallback optional fallback function to provide * permissions for file system that don't support * PosixFilePermissions. The Path corresponding to the file is * passed to the callback. * @return the permissions * @throws IOException if something goes wrong + * @sine Ant 1.10.16 */ public static Set<PosixFilePermission> getPermissions(Resource r, + boolean readFromLinkTarget, Function<Path, Set<PosixFilePermission>> posixNotSupportedFallback) throws IOException { FileProvider f = r.as(FileProvider.class); if (f != null) { Path p = f.getFile().toPath(); - PosixFileAttributeView view = - Files.getFileAttributeView(p, PosixFileAttributeView.class); + PosixFileAttributeView view = readFromLinkTarget + ? Files.getFileAttributeView(p, PosixFileAttributeView.class) + : Files.getFileAttributeView(p, PosixFileAttributeView.class, LinkOption.NOFOLLOW_LINKS); if (view != null) { return view.readAttributes().permissions(); } else if (posixNotSupportedFallback != null) {
