diff --git a/manual/Tasks/setpermissions.html b/manual/Tasks/setpermissions.html index 6d0189ede..22a6fb815 100644 --- a/manual/Tasks/setpermissions.html +++ b/manual/Tasks/setpermissions.html @@ -65,6 +65,19 @@ three-digit octal number. No + + nonPosixMode + What to do if changing the permissions of a file + is not possible because the file-system doesn't support POSIX + file permissions. Possible options are fail (fail + the build), pass (just log an + error), tryDosOrFail (at least try to set the + read-only flag on DOS file systems, fail if that isn't possible + either) and tryDosOrPass (at least try to set the + read-only flag on DOS file systems, just log an error if that + isn't possible either). + No, defaults to fail + failonerror Whether to stop the build if setting permissions diff --git a/src/main/org/apache/tools/ant/taskdefs/SetPermissions.java b/src/main/org/apache/tools/ant/taskdefs/SetPermissions.java index f06c4af9e..e78914bc9 100644 --- a/src/main/org/apache/tools/ant/taskdefs/SetPermissions.java +++ b/src/main/org/apache/tools/ant/taskdefs/SetPermissions.java @@ -19,6 +19,9 @@ package org.apache.tools.ant.taskdefs; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.DosFileAttributeView; import java.nio.file.attribute.PosixFilePermission; import java.util.Arrays; import java.util.EnumSet; @@ -38,7 +41,13 @@ import org.apache.tools.ant.util.StringUtils; * *

This task provides a subset of {@link Chmod}'s and {@link * org.apache.tools.ant.taskdefs.optional.windows.Attrib}'s abilities - * in a platform independent way.

+ * in less platform dependent way.

+ * + *

It requires a file system that supports PosixFilePermissions for + * its full potential. It can optionally fall back to + * DosFilePermissions (only changing the readonly state) on file + * systems that don't support POSIX permissions. See {@link + * SetPermissions.NonPosixMode}

* * @since Ant 1.10.0 */ @@ -47,6 +56,28 @@ public class SetPermissions extends Task { EnumSet.noneOf(PosixFilePermission.class); private Resources resources = null; private boolean failonerror = true; + private NonPosixMode nonPosixMode = NonPosixMode.fail; + + /** + * Options for dealing with file systems that don't support POSIX + * permissions. + */ + public enum NonPosixMode { + /** Fail the build. */ + fail, + /** Log an error and go on. */ + pass, + /** + * Try DosFilePermissions - setting the read-only flag - and + * fail the build if that fails as well. + */ + tryDosOrFail, + /** + * Try DosFilePermissions - setting the read-only flag - and + * log an error and go on if that fails as well. + */ + tryDosOrPass; + } /** * Adds permissions as a comma separated list. @@ -75,12 +106,26 @@ public class SetPermissions extends Task { /** * Set whether to fail when errors are encountered. If false, note errors * to the output but keep going. Default is true. + *

Only applies to IO and SecurityExceptions, see {@link + * #setNonPosixMode} for ways to deal with file-systems that don't + * support PosixPermissions.

* @param failonerror true or false. */ public void setFailOnError(final boolean failonerror) { this.failonerror = failonerror; } + /** + * Set what to do if changing the permissions of a file is not + * possible because the file-system doesn't support POSIX file + * permissions. + *

The default is {@link NonPosixMode#fail}.

+ * @param m what to do if changing the permissions of a file is not possible + */ + public void setNonPosixMode(NonPosixMode m) { + this.nonPosixMode = m; + } + /** * Adds a collection of resources to set permissions on. * @param rc a resource collection @@ -101,13 +146,11 @@ public class SetPermissions extends Task { for (Resource r : resources) { currentResource = r; try { - PermissionUtils.setPermissions(r, permissions, null); + PermissionUtils.setPermissions(r, permissions, this::posixPermissionsNotSupported); } catch (IOException ioe) { maybeThrowException(ioe, "Failed to set permissions on '%s' due to %s", r, ioe.getMessage()); } } - } catch (UnsupportedOperationException uoe) { - maybeThrowException(null, "the associated file system of resource '%s' does not support the PosixFileAttributeView", currentResource); } catch (ClassCastException uoe) { maybeThrowException(null, "some specified permissions are not of type PosixFilePermission: %s", StringUtils.join(permissions, ", ")); } catch (SecurityException uoe) { @@ -123,4 +166,55 @@ public class SetPermissions extends Task { log("Warning: " + msg, Project.MSG_ERR); } } + + private void posixPermissionsNotSupported(Path p) { + String msg = String.format("the associated path '%s' does" + + " not support the PosixFileAttributeView", p); + switch (nonPosixMode) { + case fail: + throw new BuildException(msg); + case pass: + log("Warning: " + msg, Project.MSG_ERR); + break; + case tryDosOrFail: + tryDos(p, true); + break; + case tryDosOrPass: + tryDos(p, false); + break; + } + } + + private void tryDos(Path p, boolean failIfDosIsNotSupported) { + log("Falling back to DosFileAttributeView"); + boolean readOnly = !isWritable(); + DosFileAttributeView view = Files.getFileAttributeView(p, DosFileAttributeView.class); + if (view != null) { + try { + view.setReadOnly(readOnly); + } catch (IOException ioe) { + maybeThrowException(ioe, "Failed to set permissions on '%s' due to %s", + p, ioe.getMessage()); + } catch (SecurityException uoe) { + maybeThrowException(null, "the SecurityManager denies role " + + "accessUserInformation or write access for " + + "SecurityManager.checkWrite for resource '%s'", + p); + } + } else { + String msg = String.format("the associated path '%s' does" + + " not support the DosFileAttributeView", p); + if (failIfDosIsNotSupported) { + throw new BuildException(msg); + } else { + log("Warning: " + msg, Project.MSG_ERR); + } + } + } + + private boolean isWritable() { + return permissions.contains(PosixFilePermission.OWNER_WRITE) + || permissions.contains(PosixFilePermission.GROUP_WRITE) + || permissions.contains(PosixFilePermission.OTHERS_WRITE); + } } diff --git a/src/tests/antunit/taskdefs/setpermissions-test.xml b/src/tests/antunit/taskdefs/setpermissions-test.xml index 61f771ccc..99b90e078 100644 --- a/src/tests/antunit/taskdefs/setpermissions-test.xml +++ b/src/tests/antunit/taskdefs/setpermissions-test.xml @@ -33,7 +33,8 @@ - + @@ -50,7 +51,7 @@ - +