diff --git a/src/main/java/org/junit/rules/TemporaryFolder.java b/src/main/java/org/junit/rules/TemporaryFolder.java index 1a6a77060805..a726c66e36aa 100644 --- a/src/main/java/org/junit/rules/TemporaryFolder.java +++ b/src/main/java/org/junit/rules/TemporaryFolder.java @@ -4,6 +4,9 @@ import java.io.File; import java.io.IOException; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import org.junit.Rule; @@ -229,7 +232,45 @@ public File newFolder() throws IOException { return createTemporaryFolderIn(getRoot()); } - private File createTemporaryFolderIn(File parentFolder) throws IOException { + private static File createTemporaryFolderIn(File parentFolder) throws IOException { + try { + return createTemporaryFolderWithNioApi(parentFolder); + } catch (ClassNotFoundException ignore) { + // Fallback for Java 5 and 6 + return createTemporaryFolderWithFileApi(parentFolder); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof IOException) { + throw (IOException) cause; + } + if (cause instanceof RuntimeException) { + throw (RuntimeException) cause; + } + IOException exception = new IOException("Failed to create temporary folder in " + parentFolder); + exception.initCause(cause); + throw exception; + } catch (Exception e) { + throw new RuntimeException("Failed to create temporary folder in " + parentFolder, e); + } + } + + private static File createTemporaryFolderWithNioApi(File parentFolder) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class filesClass = Class.forName("java.nio.file.Files"); + Object fileAttributeArray = Array.newInstance(Class.forName("java.nio.file.attribute.FileAttribute"), 0); + Class pathClass = Class.forName("java.nio.file.Path"); + Object tempDir; + if (parentFolder != null) { + Method createTempDirectoryMethod = filesClass.getDeclaredMethod("createTempDirectory", pathClass, String.class, fileAttributeArray.getClass()); + Object parentPath = File.class.getDeclaredMethod("toPath").invoke(parentFolder); + tempDir = createTempDirectoryMethod.invoke(null, parentPath, TMP_PREFIX, fileAttributeArray); + } else { + Method createTempDirectoryMethod = filesClass.getDeclaredMethod("createTempDirectory", String.class, fileAttributeArray.getClass()); + tempDir = createTempDirectoryMethod.invoke(null, TMP_PREFIX, fileAttributeArray); + } + return (File) pathClass.getDeclaredMethod("toFile").invoke(tempDir); + } + + private static File createTemporaryFolderWithFileApi(File parentFolder) throws IOException { File createdFolder = null; for (int i = 0; i < TEMP_DIR_ATTEMPTS; ++i) { // Use createTempFile to get a suitable folder name. diff --git a/src/test/java/org/junit/rules/TempFolderRuleTest.java b/src/test/java/org/junit/rules/TempFolderRuleTest.java index 0a82a60284cf..b120e71e610e 100644 --- a/src/test/java/org/junit/rules/TempFolderRuleTest.java +++ b/src/test/java/org/junit/rules/TempFolderRuleTest.java @@ -3,21 +3,28 @@ import static org.hamcrest.CoreMatchers.hasItem; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsNot.not; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import static org.junit.experimental.results.PrintableResult.testResult; import static org.junit.experimental.results.ResultMatchers.failureCountIs; import static org.junit.experimental.results.ResultMatchers.isSuccessful; import java.io.File; import java.io.IOException; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import org.junit.After; +import org.junit.AssumptionViolatedException; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TemporaryFolder; public class TempFolderRuleTest { private static File[] createdFiles = new File[20]; @@ -182,6 +189,34 @@ public void recursiveDeleteFolderWithZeroElements() throws IOException { assertFalse(folder.getRoot().exists()); } + @Test + public void tempFolderIsOnlyAccessibleByOwner() throws IOException { + TemporaryFolder folder = new TemporaryFolder(); + folder.create(); + + Set expectedPermissions = new TreeSet(Arrays.asList("OWNER_READ", "OWNER_WRITE", "OWNER_EXECUTE")); + Set actualPermissions = getPosixFilePermissions(folder.getRoot()); + assertEquals(expectedPermissions, actualPermissions); + } + + private Set getPosixFilePermissions(File root) { + try { + Class pathClass = Class.forName("java.nio.file.Path"); + Object linkOptionArray = Array.newInstance(Class.forName("java.nio.file.LinkOption"), 0); + Class filesClass = Class.forName("java.nio.file.Files"); + Object path = File.class.getDeclaredMethod("toPath").invoke(root); + Method posixFilePermissionsMethod = filesClass.getDeclaredMethod("getPosixFilePermissions", pathClass, linkOptionArray.getClass()); + Set permissions = (Set) posixFilePermissionsMethod.invoke(null, path, linkOptionArray); + SortedSet convertedPermissions = new TreeSet(); + for (Object item : permissions) { + convertedPermissions.add(item.toString()); + } + return convertedPermissions; + } catch (Exception e) { + throw new AssumptionViolatedException("Test requires at least Java 1.7", e); + } + } + public static class NameClashes { @Rule public TemporaryFolder folder = new TemporaryFolder();