You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by bo...@apache.org on 2016/04/17 11:59:06 UTC

ant git commit: helper class for dealing with file permissions

Repository: ant
Updated Branches:
  refs/heads/master f6e6c20a8 -> 97a0b26c7


helper class for dealing with file permissions


Project: http://git-wip-us.apache.org/repos/asf/ant/repo
Commit: http://git-wip-us.apache.org/repos/asf/ant/commit/97a0b26c
Tree: http://git-wip-us.apache.org/repos/asf/ant/tree/97a0b26c
Diff: http://git-wip-us.apache.org/repos/asf/ant/diff/97a0b26c

Branch: refs/heads/master
Commit: 97a0b26c7e3aa1df286f2c318d6433f7b3d2023f
Parents: f6e6c20
Author: Stefan Bodewig <bo...@apache.org>
Authored: Sun Apr 17 11:58:40 2016 +0200
Committer: Stefan Bodewig <bo...@apache.org>
Committed: Sun Apr 17 11:58:40 2016 +0200

----------------------------------------------------------------------
 .../apache/tools/ant/util/PermissionUtils.java  | 207 +++++++++++++++++++
 .../tools/ant/util/PermissionUtilsTest.java     | 155 ++++++++++++++
 2 files changed, 362 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ant/blob/97a0b26c/src/main/org/apache/tools/ant/util/PermissionUtils.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/util/PermissionUtils.java b/src/main/org/apache/tools/ant/util/PermissionUtils.java
new file mode 100644
index 0000000..6fbf163
--- /dev/null
+++ b/src/main/org/apache/tools/ant/util/PermissionUtils.java
@@ -0,0 +1,207 @@
+/*
+ *  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.util;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.resources.ArchiveResource;
+import org.apache.tools.ant.types.resources.FileProvider;
+
+/**
+ * Contains helper methods for dealing with {@link
+ * PosixFilePermission} or the traditional Unix mode representation of
+ * permissions.
+ *
+ * @since Ant 1.10.0
+ */
+public class PermissionUtils {
+
+    private PermissionUtils() { }
+
+    /**
+     * Translates a set of permissons into a Unix stat(2) {@code
+     * st_mode} result.
+     * @param permissions the permissions
+     * @param type the file type
+     * @return the "mode"
+     */
+    public static int modeFromPermissions(Set<PosixFilePermission> permissions,
+                                           FileType type) {
+        int mode;
+        switch (type) {
+        case SYMLINK:
+            mode = 012;
+            break;
+        case REGULAR_FILE:
+            mode = 010;
+            break;
+        case DIR:
+            mode = 004;
+            break;
+        default:
+            // OTHER could be a character or block device, a socket or a FIFO - so don't set anything
+            mode = 0;
+            break;
+        }
+        mode <<= 3;
+        mode <<= 3; // we don't support sticky, setuid, setgid
+        mode |= modeFromPermissions(permissions, "OWNER");
+        mode <<= 3;
+        mode |= modeFromPermissions(permissions, "GROUP");
+        mode <<= 3;
+        mode |= modeFromPermissions(permissions, "OTHERS");
+        return mode;
+    }
+
+    /**
+     * Translates a Unix stat(2) {@code st_mode} compatible value into
+     * a set of permissions.
+     * @param mode the "mode"
+     * @return set of permissions
+     */
+    public static Set<PosixFilePermission> permissionsFromMode(int mode) {
+        Set<PosixFilePermission> permissions = EnumSet.noneOf(PosixFilePermission.class);
+        addPermissions(permissions, "OTHERS", mode);
+        addPermissions(permissions, "GROUP", mode >> 3);
+        addPermissions(permissions, "OWNER", mode >> 6);
+        return permissions;
+    }
+
+    /**
+     * 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 resource the resource to set permissions for
+     * @param permissions the permissions
+     */
+    public static void setPermissions(Resource r, Set<PosixFilePermission> permissions)
+        throws IOException {
+        FileProvider f = r.as(FileProvider.class);
+        if (f != null) {
+            Files.setPosixFilePermissions(f.getFile().toPath(), permissions);
+        } else if (r instanceof ArchiveResource) {
+            ((ArchiveResource) r).setMode(modeFromPermissions(permissions,
+                                                              FileType.of(r)));
+        }
+    }
+
+    /**
+     * Sets permissions of a {@link Resource} - doesn't returns an
+     * empty set for unsupported resource types.
+     *
+     * <p>Supported types are:</p>
+     * <ul>
+     *  <li>any {@link FileProvider}</li>
+     *  <li>{@link ArchiveResource}</li>
+     * </ul>
+     *
+     * @param resource the resource to read permissions from
+     * @return the permissions
+     */
+    public static Set<PosixFilePermission> getPermissions(Resource r) throws IOException {
+        FileProvider f = r.as(FileProvider.class);
+        if (f != null) {
+            return Files.getPosixFilePermissions(f.getFile().toPath());
+        } else if (r instanceof ArchiveResource) {
+            return permissionsFromMode(((ArchiveResource) r).getMode());
+        }
+        return EnumSet.noneOf(PosixFilePermission.class);
+    }
+
+    private static long modeFromPermissions(Set<PosixFilePermission> permissions,
+                                            String prefix) {
+        long mode = 0;
+        if (permissions.contains(PosixFilePermission.valueOf(prefix + "_READ"))) {
+            mode |= 4;
+        }
+        if (permissions.contains(PosixFilePermission.valueOf(prefix + "_WRITE"))) {
+            mode |= 2;
+        }
+        if (permissions.contains(PosixFilePermission.valueOf(prefix + "_EXECUTE"))) {
+            mode |= 1;
+        }
+        return mode;
+    }
+
+    private static void addPermissions(Set<PosixFilePermission> permissions,
+                                       String prefix, long mode) {
+        if ((mode & 1) == 1) {
+            permissions.add(PosixFilePermission.valueOf(prefix + "_EXECUTE"));
+        }
+        if ((mode & 2) == 2) {
+            permissions.add(PosixFilePermission.valueOf(prefix + "_WRITE"));
+        }
+        if ((mode & 4) == 4) {
+            permissions.add(PosixFilePermission.valueOf(prefix + "_READ"));
+        }
+    }
+
+    /**
+     * The supported types of files, maps to the {@code isFoo} methods
+     * in {@link java.nio.file.attribute.BasicFileAttributes}.
+     */
+    public enum FileType {
+        /** A regular file. */
+        REGULAR_FILE,
+        /** A directory. */
+        DIR,
+        /** A symbolic link. */
+        SYMLINK,
+        /** Something that is neither a regular file nor a directory nor a symbolic link. */
+        OTHER;
+
+        /**
+         * Determines the file type of a {@link Path}.
+         */
+        public static FileType of(Path p) throws IOException {
+            BasicFileAttributes attrs =
+                Files.readAttributes(p, BasicFileAttributes.class);
+            if (attrs.isRegularFile()) {
+                return FileType.REGULAR_FILE;
+            } else if (attrs.isDirectory()) {
+                return FileType.DIR;
+            } else if (attrs.isSymbolicLink()) {
+                return FileType.SYMLINK;
+            }
+            return FileType.OTHER;
+        }
+
+        /**
+         * Determines the file type of a {@link Resource}.
+         */
+        public static FileType of(Resource r) {
+            if (r.isDirectory()) {
+                return FileType.DIR;
+            }
+            return FileType.REGULAR_FILE;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ant/blob/97a0b26c/src/tests/junit/org/apache/tools/ant/util/PermissionUtilsTest.java
----------------------------------------------------------------------
diff --git a/src/tests/junit/org/apache/tools/ant/util/PermissionUtilsTest.java b/src/tests/junit/org/apache/tools/ant/util/PermissionUtilsTest.java
new file mode 100644
index 0000000..eed265d
--- /dev/null
+++ b/src/tests/junit/org/apache/tools/ant/util/PermissionUtilsTest.java
@@ -0,0 +1,155 @@
+/*
+ *  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.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.TarResource;
+import org.apache.tools.ant.types.resources.ZipResource;
+import org.apache.tools.tar.TarEntry;
+import org.apache.tools.tar.TarOutputStream;
+import org.apache.tools.zip.ZipEntry;
+import org.apache.tools.zip.ZipOutputStream;
+import org.junit.Test;
+
+public class PermissionUtilsTest {
+
+    @Test
+    public void modeFromPermissionsReturnsExpectedResult() {
+        int mode = PermissionUtils.modeFromPermissions(EnumSet.of(PosixFilePermission.OWNER_READ,
+                                                                  PosixFilePermission.OWNER_WRITE,
+                                                                  PosixFilePermission.OWNER_EXECUTE),
+                                                       PermissionUtils.FileType.REGULAR_FILE);
+        assertEquals("100700", Integer.toString(mode, 8));
+    }
+
+    @Test
+    public void permissionsFromModeReturnsExpectedResult() {
+        Set<PosixFilePermission> s = PermissionUtils.permissionsFromMode(0100753);
+        assertEquals(EnumSet.of(PosixFilePermission.OWNER_READ,
+                                PosixFilePermission.OWNER_WRITE,
+                                PosixFilePermission.OWNER_EXECUTE,
+                                PosixFilePermission.GROUP_READ,
+                                PosixFilePermission.GROUP_EXECUTE,
+                                PosixFilePermission.OTHERS_WRITE,
+                                PosixFilePermission.OTHERS_EXECUTE),
+                     s);
+    }
+
+    @Test
+    public void detectsFileTypeOfRegularFileFromPath() throws IOException {
+        File f = File.createTempFile("ant", ".tst");
+        f.deleteOnExit();
+        assertEquals(PermissionUtils.FileType.REGULAR_FILE,
+                     PermissionUtils.FileType.of(f.toPath()));
+    }
+
+    @Test
+    public void detectsFileTypeOfRegularFileFromResource() throws IOException {
+        File f = File.createTempFile("ant", ".tst");
+        f.deleteOnExit();
+        assertEquals(PermissionUtils.FileType.REGULAR_FILE,
+                     PermissionUtils.FileType.of(new FileResource(f)));
+    }
+
+    @Test
+    public void detectsFileTypeOfDirectoryFromPath() throws IOException {
+        File f = File.createTempFile("ant", ".dir");
+        f.delete();
+        f.mkdirs();
+        f.deleteOnExit();
+        assertEquals(PermissionUtils.FileType.DIR,
+                     PermissionUtils.FileType.of(f.toPath()));
+    }
+
+    @Test
+    public void detectsFileTypeOfDirectoryFromResource() throws IOException {
+        File f = File.createTempFile("ant", ".tst");
+        f.delete();
+        f.mkdirs();
+        f.deleteOnExit();
+        assertEquals(PermissionUtils.FileType.DIR,
+                     PermissionUtils.FileType.of(new FileResource(f)));
+    }
+
+    @Test
+    public void getSetPermissionsWorksForFiles() throws IOException {
+        File f = File.createTempFile("ant", ".tst");
+        f.deleteOnExit();
+        Set<PosixFilePermission> s =
+            EnumSet.of(PosixFilePermission.OWNER_READ,
+                       PosixFilePermission.OWNER_WRITE,
+                       PosixFilePermission.OWNER_EXECUTE,
+                       PosixFilePermission.GROUP_READ);
+        PermissionUtils.setPermissions(new FileResource(f), s);
+        assertEquals(s, PermissionUtils.getPermissions(new FileResource(f)));
+    }
+
+    @Test
+    public void getSetPermissionsWorksForZipResources() throws IOException {
+        File f = File.createTempFile("ant", ".zip");
+        f.deleteOnExit();
+        try (ZipOutputStream os = new ZipOutputStream(f)) {
+            ZipEntry e = new ZipEntry("foo");
+            os.putNextEntry(e);
+            os.closeEntry();
+        }
+
+        ZipResource r = new ZipResource();
+        r.setName("foo");
+        r.setArchive(f);
+        Set<PosixFilePermission> s =
+            EnumSet.of(PosixFilePermission.OWNER_READ,
+                       PosixFilePermission.OWNER_WRITE,
+                       PosixFilePermission.OWNER_EXECUTE,
+                       PosixFilePermission.GROUP_READ);
+        PermissionUtils.setPermissions(r, s);
+        assertEquals(s, PermissionUtils.getPermissions(r));
+    }
+
+    @Test
+    public void getSetPermissionsWorksForTarResources() throws IOException {
+        File f = File.createTempFile("ant", ".zip");
+        f.deleteOnExit();
+        try (TarOutputStream os = new TarOutputStream(new FileOutputStream(f))) {
+            TarEntry e = new TarEntry("foo");
+            os.putNextEntry(e);
+            os.closeEntry();
+        }
+
+        TarResource r = new TarResource();
+        r.setName("foo");
+        r.setArchive(f);
+        Set<PosixFilePermission> s =
+            EnumSet.of(PosixFilePermission.OWNER_READ,
+                       PosixFilePermission.OWNER_WRITE,
+                       PosixFilePermission.OWNER_EXECUTE,
+                       PosixFilePermission.GROUP_READ);
+        PermissionUtils.setPermissions(r, s);
+        assertEquals(s, PermissionUtils.getPermissions(r));
+    }
+}