Browse Source

helper class for dealing with file permissions

master
Stefan Bodewig 9 years ago
parent
commit
97a0b26c7e
2 changed files with 362 additions and 0 deletions
  1. +207
    -0
      src/main/org/apache/tools/ant/util/PermissionUtils.java
  2. +155
    -0
      src/tests/junit/org/apache/tools/ant/util/PermissionUtilsTest.java

+ 207
- 0
src/main/org/apache/tools/ant/util/PermissionUtils.java View File

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

+ 155
- 0
src/tests/junit/org/apache/tools/ant/util/PermissionUtilsTest.java View File

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

Loading…
Cancel
Save