This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-io.git
commit 4848ddde2f1e11bd83efa2ec624e1624a7191c4e Author: Gary Gregory <gardgreg...@gmail.com> AuthorDate: Sun Feb 6 14:38:13 2022 -0500 Restore some behavior based on findings described in https://github.com/apache/commons-io/pull/324 --- .../java/org/apache/commons/io/file/PathUtils.java | 23 +++-- .../java/org/apache/commons/io/FileUtilsTest.java | 108 +++++++++++++-------- .../org/apache/commons/io/file/PathUtilsTest.java | 27 +++--- 3 files changed, 100 insertions(+), 58 deletions(-) diff --git a/src/main/java/org/apache/commons/io/file/PathUtils.java b/src/main/java/org/apache/commons/io/file/PathUtils.java index 1795eed..a88781a 100644 --- a/src/main/java/org/apache/commons/io/file/PathUtils.java +++ b/src/main/java/org/apache/commons/io/file/PathUtils.java @@ -53,6 +53,7 @@ import java.nio.file.attribute.PosixFilePermission; import java.time.Duration; import java.time.Instant; import java.time.chrono.ChronoZonedDateTime; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -176,13 +177,13 @@ public final class PathUtils { * @since 2.9.0 */ public static final LinkOption[] NOFOLLOW_LINK_OPTION_ARRAY = {LinkOption.NOFOLLOW_LINKS}; - + /** * A LinkOption used to follow link in this class, the inverse of {@link LinkOption#NOFOLLOW_LINKS}. * * @since 2.12.0 */ - public static final LinkOption FOLLOW_LINKS = null; + static final LinkOption NULL_LINK_OPTION = null; /** * Empty {@link OpenOption} array. @@ -362,7 +363,7 @@ public final class PathUtils { return parent == null ? null : Files.createDirectories(parent, attrs); } - private static Path readIfSymbolicLink(Path path) throws IOException { + private static Path readIfSymbolicLink(final Path path) throws IOException { return Files.isSymbolicLink(path) ? Files.readSymbolicLink(path) : path; } @@ -650,7 +651,8 @@ public final class PathUtils { } private static boolean exists(final Path path, final LinkOption... options) { - return Files.exists(Objects.requireNonNull(path, "path"), options); + Objects.requireNonNull(path, "path"); + return options != null ? Files.exists(path, options) : Files.exists(path); } /** @@ -1087,14 +1089,19 @@ public final class PathUtils { * @since 2.12.0 */ public static OutputStream newOutputStream(final Path path, final boolean append) throws IOException { - Objects.requireNonNull(path, "path"); - if (exists(path)) { + return newOutputStream(path, EMPTY_LINK_OPTION_ARRAY, append ? OPEN_OPTIONS_APPEND : OPEN_OPTIONS_TRUNCATE); + } + + static OutputStream newOutputStream(final Path path, final LinkOption[] linkOptions, final OpenOption... openOptions) throws IOException { + if (exists(path, linkOptions)) { // requireFile(path, "path"); // requireCanWrite(path, "path"); } else { - createParentDirectories(path); + createParentDirectories(path, linkOptions != null && linkOptions.length > 0 ? linkOptions[0] : NULL_LINK_OPTION); } - return Files.newOutputStream(path, append ? OPEN_OPTIONS_APPEND : OPEN_OPTIONS_TRUNCATE); + final List<OpenOption> list = new ArrayList<>(Arrays.asList(openOptions != null ? openOptions : EMPTY_OPEN_OPTION_ARRAY)); + list.addAll(Arrays.asList(linkOptions != null ? linkOptions : EMPTY_LINK_OPTION_ARRAY)); + return Files.newOutputStream(path, list.toArray(EMPTY_OPEN_OPTION_ARRAY)); } private static boolean notExists(final Path path, final LinkOption... options) { diff --git a/src/test/java/org/apache/commons/io/FileUtilsTest.java b/src/test/java/org/apache/commons/io/FileUtilsTest.java index 1e75d3f..f64451c 100644 --- a/src/test/java/org/apache/commons/io/FileUtilsTest.java +++ b/src/test/java/org/apache/commons/io/FileUtilsTest.java @@ -251,6 +251,14 @@ public class FileUtilsTest extends AbstractTempDirTest { FileUtils.writeStringToFile(file6, "File 6 in grandChild2", "UTF8"); } + private Path createTempSymlinkedRelativeDir() throws IOException { + final Path targetDir = tempDirPath.resolve("subdir"); + final Path symlinkDir = tempDirPath.resolve("symlinked-dir"); + Files.createDirectory(targetDir); + Files.createSymbolicLink(symlinkDir, targetDir); + return symlinkDir; + } + private long getLastModifiedMillis(final File file) throws IOException { return FileUtils.lastModified(file); } @@ -391,6 +399,17 @@ public class FileUtilsTest extends AbstractTempDirTest { } @Test + public void test_openOutputStream_intoExistingSymlinkedDir() throws Exception { + final Path symlinkedDir = createTempSymlinkedRelativeDir(); + + final File file = symlinkedDir.resolve("test.txt").toFile(); + try (FileOutputStream out = FileUtils.openOutputStream(file)) { + out.write(0); + } + assertTrue(file.exists()); + } + + @Test public void test_openOutputStream_noParentCreateFile() throws Exception { openOutputStream_noParent(true); } @@ -823,23 +842,6 @@ public class FileUtilsTest extends AbstractTempDirTest { FileUtils.deleteDirectory(target); } - /* Test for IO-141 */ - @Test - public void testCopyDirectoryToChild() throws Exception { - final File grandParentDir = new File(tempDirFile, "grandparent"); - final File parentDir = new File(grandParentDir, "parent"); - final File childDir = new File(parentDir, "child"); - createFilesForTestCopyDirectory(grandParentDir, parentDir, childDir); - - final long expectedCount = LIST_WALKER.list(grandParentDir).size() + LIST_WALKER.list(parentDir).size(); - final long expectedSize = FileUtils.sizeOfDirectory(grandParentDir) + FileUtils.sizeOfDirectory(parentDir); - FileUtils.copyDirectory(parentDir, childDir); - assertEquals(expectedCount, LIST_WALKER.list(grandParentDir).size()); - assertEquals(expectedSize, FileUtils.sizeOfDirectory(grandParentDir)); - assertTrue(expectedCount > 0, "Count > 0"); - assertTrue(expectedSize > 0, "Size > 0"); - } - // @Test public void testToURLs2() throws Exception { // File[] files = new File[] { // new File(temporaryFolder, "file1.txt"), @@ -860,6 +862,23 @@ public class FileUtilsTest extends AbstractTempDirTest { // assertEquals(0, urls.length); // } + /* Test for IO-141 */ + @Test + public void testCopyDirectoryToChild() throws Exception { + final File grandParentDir = new File(tempDirFile, "grandparent"); + final File parentDir = new File(grandParentDir, "parent"); + final File childDir = new File(parentDir, "child"); + createFilesForTestCopyDirectory(grandParentDir, parentDir, childDir); + + final long expectedCount = LIST_WALKER.list(grandParentDir).size() + LIST_WALKER.list(parentDir).size(); + final long expectedSize = FileUtils.sizeOfDirectory(grandParentDir) + FileUtils.sizeOfDirectory(parentDir); + FileUtils.copyDirectory(parentDir, childDir); + assertEquals(expectedCount, LIST_WALKER.list(grandParentDir).size()); + assertEquals(expectedSize, FileUtils.sizeOfDirectory(grandParentDir)); + assertTrue(expectedCount > 0, "Count > 0"); + assertTrue(expectedSize > 0, "Size > 0"); + } + @Test public void testCopyDirectoryToDirectory_NonExistingDest() throws Exception { if (!testFile1.getParentFile().exists()) { @@ -1339,6 +1358,8 @@ public class FileUtilsTest extends AbstractTempDirTest { assertThrows(IllegalArgumentException.class, () -> FileUtils.deleteDirectory(testFile1)); } + // copyToDirectory + @Test public void testDeleteQuietlyDir() throws IOException { final File testDirectory = new File(tempDirFile, "testDeleteQuietlyDir"); @@ -1363,8 +1384,6 @@ public class FileUtilsTest extends AbstractTempDirTest { assertFalse(testFile.exists(), "Check No Exist"); } - // copyToDirectory - @Test public void testDeleteQuietlyFile() throws IOException { final File testFile = new File(tempDirFile, "testDeleteQuietlyFile"); @@ -2428,6 +2447,7 @@ public class FileUtilsTest extends AbstractTempDirTest { assertEquals(31, data[2]); } + @Test public void testReadFileToStringWithDefaultEncoding() throws Exception { final File file = new File(tempDirFile, "read.obj"); @@ -2440,7 +2460,6 @@ public class FileUtilsTest extends AbstractTempDirTest { assertEquals("Hello /u1234", data); } - @Test public void testReadFileToStringWithEncoding() throws Exception { final File file = new File(tempDirFile, "read.obj"); @@ -2872,6 +2891,7 @@ public class FileUtilsTest extends AbstractTempDirTest { assertEquals(expected, actual); } + @Test public void testWriteLines_3argsWithAppendOptionTrue_ShouldNotDeletePreviousFileLines() throws Exception { final File file = TestUtils.newFile(tempDirFile, "lines.txt"); @@ -2888,7 +2908,6 @@ public class FileUtilsTest extends AbstractTempDirTest { assertEquals(expected, actual); } - @Test public void testWriteLines_4arg() throws Exception { final Object[] data = { @@ -3046,34 +3065,29 @@ public class FileUtilsTest extends AbstractTempDirTest { } @Test - public void testWriteStringToFile1() throws Exception { - final File file = new File(tempDirFile, "write.txt"); - FileUtils.writeStringToFile(file, "Hello /u1234", "UTF8"); - final byte[] text = "Hello /u1234".getBytes(StandardCharsets.UTF_8); - TestUtils.assertEqualContent(text, file); - } - - @Test - public void testWriteStringToFile2() throws Exception { - final File file = new File(tempDirFile, "write.txt"); - FileUtils.writeStringToFile(file, "Hello /u1234", (String) null); + public void testWriteStringToFileIntoNonExistentSubdir() throws Exception { + final File file = new File(tempDirFile, "subdir/write.txt"); + FileUtils.writeStringToFile(file, "Hello /u1234", (Charset) null); final byte[] text = "Hello /u1234".getBytes(); TestUtils.assertEqualContent(text, file); } @Test - public void testWriteStringToFile3() throws Exception { - final File file = new File(tempDirFile, "write.txt"); - FileUtils.writeStringToFile(file, "Hello /u1234", (Charset) null); + public void testWriteStringToFileIntoSymlinkedDir() throws Exception { + final Path symlinkDir = createTempSymlinkedRelativeDir(); + + final File file = symlinkDir.resolve("file").toFile(); + FileUtils.writeStringToFile(file, "Hello /u1234", StandardCharsets.UTF_8); + final byte[] text = "Hello /u1234".getBytes(); TestUtils.assertEqualContent(text, file); } @Test - public void testWriteStringToFile4() throws Exception { - final File file = new File(tempDirFile, "subdir/write.txt"); - FileUtils.writeStringToFile(file, "Hello /u1234", (Charset) null); - final byte[] text = "Hello /u1234".getBytes(); + public void testWriteStringToFileWithCharset() throws Exception { + final File file = new File(tempDirFile, "write.txt"); + FileUtils.writeStringToFile(file, "Hello /u1234", "UTF8"); + final byte[] text = "Hello /u1234".getBytes(StandardCharsets.UTF_8); TestUtils.assertEqualContent(text, file); } @@ -3103,6 +3117,22 @@ public class FileUtilsTest extends AbstractTempDirTest { } @Test + public void testWriteStringToFileWithNullCharset() throws Exception { + final File file = new File(tempDirFile, "write.txt"); + FileUtils.writeStringToFile(file, "Hello /u1234", (Charset) null); + final byte[] text = "Hello /u1234".getBytes(); + TestUtils.assertEqualContent(text, file); + } + + @Test + public void testWriteStringToFileWithNullStringCharset() throws Exception { + final File file = new File(tempDirFile, "write.txt"); + FileUtils.writeStringToFile(file, "Hello /u1234", (String) null); + final byte[] text = "Hello /u1234".getBytes(); + TestUtils.assertEqualContent(text, file); + } + + @Test public void testWriteWithEncoding_WithAppendOptionFalse_ShouldDeletePreviousFileLines() throws Exception { final File file = TestUtils.newFile(tempDirFile, "lines.txt"); FileUtils.writeStringToFile(file, "This line was there before you..."); diff --git a/src/test/java/org/apache/commons/io/file/PathUtilsTest.java b/src/test/java/org/apache/commons/io/file/PathUtilsTest.java index 6048b78..9f7427d 100644 --- a/src/test/java/org/apache/commons/io/file/PathUtilsTest.java +++ b/src/test/java/org/apache/commons/io/file/PathUtilsTest.java @@ -33,6 +33,7 @@ import java.nio.file.FileAlreadyExistsException; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; +import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.DosFileAttributeView; @@ -69,7 +70,7 @@ public class PathUtilsTest extends AbstractTempDirTest { * <li>tempDirPath/subdir</li> * <li>tempDirPath/symlinked-dir -> tempDirPath/subdir</li> * </ol> - * + * * @return Path to tempDirPath/subdir * @throws IOException if an I/O error occurs or the parent directory does not exist. */ @@ -129,7 +130,7 @@ public class PathUtilsTest extends AbstractTempDirTest { public void testCopyDirectoryForDifferentFilesystemsWithRelativePath() throws IOException { final Path archivePath = Paths.get(TEST_JAR_PATH); try (final FileSystem archive = openArchive(archivePath, false); - final FileSystem targetArchive = openArchive(tempDirPath.resolve(TEST_JAR_NAME), true)) { + final FileSystem targetArchive = openArchive(tempDirPath.resolve(TEST_JAR_NAME), true)) { final Path targetDir = targetArchive.getPath("targetDir"); Files.createDirectory(targetDir); // relative jar -> relative dir @@ -183,7 +184,7 @@ public class PathUtilsTest extends AbstractTempDirTest { public void testCreateDirectoriesSymlink() throws IOException { final Path symlinkedDir = createTempSymlinkedRelativeDir(); final String leafDirName = "child"; - final Path newDirFollowed = PathUtils.createParentDirectories(symlinkedDir.resolve(leafDirName), PathUtils.FOLLOW_LINKS); + final Path newDirFollowed = PathUtils.createParentDirectories(symlinkedDir.resolve(leafDirName), PathUtils.NULL_LINK_OPTION); assertEquals(Files.readSymbolicLink(symlinkedDir), newDirFollowed); } @@ -279,14 +280,18 @@ public class PathUtilsTest extends AbstractTempDirTest { public void testNewOutputStreamNewFileInsideExistingSymlinkedDir() throws IOException { final Path symlinkDir = createTempSymlinkedRelativeDir(); final Path file = symlinkDir.resolve("test.txt"); - assertThrowsExactly(FileAlreadyExistsException.class, () -> PathUtils.newOutputStream(file, false)); - } - - @Test - public void testNewOutputStreamNewFileInsideExistingSymlinkedDirFollow() throws IOException { - final Path symlinkDir = createTempSymlinkedRelativeDir(); - final Path file = symlinkDir.resolve("test.txt"); - assertThrowsExactly(FileAlreadyExistsException.class, () -> PathUtils.newOutputStream(file, false)); + try (OutputStream outputStream = PathUtils.newOutputStream(file, new LinkOption[] {})) { + // empty + } + try (OutputStream outputStream = PathUtils.newOutputStream(file, null)) { + // empty + } + try (OutputStream outputStream = PathUtils.newOutputStream(file, true)) { + // empty + } + try (OutputStream outputStream = PathUtils.newOutputStream(file, false)) { + // empty + } } @Test