package org.zeroturnaround.zip; import java.io.File; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.HashSet; import java.util.Set; /** * ZTFilePermissionsStrategy which uses Java 7 posix file permissions * * @author VIktor Karabut */ class Java7Nio2ApiPermissionsStrategy implements ZTFilePermissionsStrategy { private final Class<? extends Enum<?>> posixFilePermissionClass; private final Class<?> filesClass; private final Class<?> pathClass; private final Class<? extends Enum<?>> linkOptionClass; private final Enum<?>[] linkOptionsArray; private final Method toPathMethod; private final Method setPosixFilePermissionsMethod; private final Method getPosixFilePermissionsMethod; private final Object OWNER_READ; private final Object OWNER_WRITE; private final Object OWNER_EXECUTE; private final Object GROUP_READ; private final Object GROUP_WRITE; private final Object GROUP_EXECUTE; private final Object OTHERS_READ; private final Object OTHERS_WRITE; private final Object OTHERS_EXECUTE; @SuppressWarnings("unchecked") public Java7Nio2ApiPermissionsStrategy() { if (!isPosix()) { throw new ZipException("File system does not support POSIX file attributes"); } posixFilePermissionClass = (Class<? extends Enum<?>>) ZTZipReflectionUtil.getClassForName("java.nio.file.attribute.PosixFilePermission", Enum.class); Enum<?>[] constants = posixFilePermissionClass.getEnumConstants(); OWNER_READ = constants[0]; OWNER_WRITE = constants[1]; OWNER_EXECUTE = constants[2]; GROUP_READ = constants[3]; GROUP_WRITE = constants[4]; GROUP_EXECUTE = constants[5]; OTHERS_READ = constants[6]; OTHERS_WRITE = constants[7]; OTHERS_EXECUTE = constants[8]; linkOptionClass = (Class<? extends Enum<?>>) ZTZipReflectionUtil.getClassForName("java.nio.file.LinkOption", Enum.class); linkOptionsArray = (Enum<?>[]) Array.newInstance(linkOptionClass, 1); linkOptionsArray[0] = (Enum<?>) linkOptionClass.getEnumConstants()[0]; // LinkOption.NOFOLLOW_LINKS; filesClass = ZTZipReflectionUtil.getClassForName("java.nio.file.Files", Object.class); pathClass = ZTZipReflectionUtil.getClassForName("java.nio.file.Path", Object.class); toPathMethod = ZTZipReflectionUtil.getDeclaredMethod(File.class, "toPath"); setPosixFilePermissionsMethod = ZTZipReflectionUtil.getDeclaredMethod(filesClass, "setPosixFilePermissions", pathClass, Set.class); getPosixFilePermissionsMethod = ZTZipReflectionUtil.getDeclaredMethod(filesClass, "getPosixFilePermissions", pathClass, linkOptionsArray.getClass()); } public ZTFilePermissions getPermissions(File file) { ZTFilePermissions permissions = new ZTFilePermissions(); permissions.setDirectory(file.isDirectory()); Set<?> posixFilePermissions = getPosixFilePermissions(file); permissions.setOwnerCanRead( posixFilePermissions.contains(OWNER_READ)); permissions.setOwnerCanWrite( posixFilePermissions.contains(OWNER_WRITE)); permissions.setOwnerCanExecute(posixFilePermissions.contains(OWNER_EXECUTE)); permissions.setGroupCanRead( posixFilePermissions.contains(GROUP_READ)); permissions.setGroupCanWrite( posixFilePermissions.contains(GROUP_WRITE)); permissions.setGroupCanExecute(posixFilePermissions.contains(GROUP_EXECUTE)); permissions.setOthersCanRead( posixFilePermissions.contains(OTHERS_READ)); permissions.setOthersCanWrite( posixFilePermissions.contains(OTHERS_WRITE)); permissions.setOthersCanExecute(posixFilePermissions.contains(OTHERS_EXECUTE)); return permissions; } public void setPermissions(File file, ZTFilePermissions permissions) { Set<Object> set = new HashSet<Object>(); addIf(permissions.isOwnerCanRead(), set, OWNER_READ); addIf(permissions.isOwnerCanRead(), set,OWNER_READ); addIf(permissions.isOwnerCanWrite(), set,OWNER_WRITE); addIf(permissions.isOwnerCanExecute(),set,OWNER_EXECUTE); addIf(permissions.isGroupCanRead(), set,GROUP_READ); addIf(permissions.isGroupCanWrite(), set,GROUP_WRITE); addIf(permissions.isGroupCanExecute(),set,GROUP_EXECUTE); addIf(permissions.isOthersCanRead(), set,OTHERS_READ); addIf(permissions.isOthersCanWrite(), set,OTHERS_WRITE); addIf(permissions.isOthersCanExecute(),set,OTHERS_EXECUTE); setPosixFilePermissions(file, set); } private <E> void addIf(boolean condition, Set<E> set, E el) { if (condition) { set.add(el); } } /** * Construct java.nio.file.Path object from abstract path. * Invokes JDK7 <code>file.toPath()</code> method through reflection. * * @param file * @return instance of java.nio.file.Path object */ private Object toPath(File file) { return ZTZipReflectionUtil.invoke(toPathMethod, file); } // Files.setPosixFilePermissions(file.toPath(), set); private void setPosixFilePermissions(File file, Set<?> set) { ZTZipReflectionUtil.invoke(setPosixFilePermissionsMethod, null, toPath(file), set); } // Files.getPosixFilePermissions(file.toPath(), new LinkOption[]{ LinkOption.NOFOLLOW_LINKS }); private Set<?> getPosixFilePermissions(File file) { return (Set<?>) ZTZipReflectionUtil.invoke(getPosixFilePermissionsMethod, null, toPath(file), linkOptionsArray); } // FileSystems.getDefault().supportedFileAttrubuteViews().contains("posix"); private static boolean isPosix() { Method getDefaultMethod = ZTZipReflectionUtil.getDeclaredMethod( ZTZipReflectionUtil.getClassForName("java.nio.file.FileSystems", Object.class), "getDefault"); Method supportedFileAttributeViewsMethod = ZTZipReflectionUtil.getDeclaredMethod( ZTZipReflectionUtil.getClassForName("java.nio.file.FileSystem", Object.class), "supportedFileAttributeViews"); Object fileSystem = ZTZipReflectionUtil.invoke(getDefaultMethod, null); @SuppressWarnings("unchecked") Set<String> views = (Set<String>) ZTZipReflectionUtil.invoke(supportedFileAttributeViewsMethod, fileSystem); return views.contains("posix"); } }