Restore some behavior based on findings described in
MODIFY
src/main/java/org/apache/commons/io/file/PathUtils.java
src/main/java/org/apache/commons/io/file/PathUtils.java
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;
@@ -182,7 +183,7 @@ private RelativeSortedPaths(final Path dir1, final Path dir2, final int maxDepth
*
* @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 static Path createParentDirectories(final Path path, final LinkOption lin
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 static boolean directoryContentEquals(final Path path1, final Path path2,
}
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 static boolean isRegularFile(final Path path, final LinkOption... options
* @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) {

MODIFY
src/test/java/org/apache/commons/io/FileUtilsTest.java
src/test/java/org/apache/commons/io/FileUtilsTest.java
@@ -251,6 +251,14 @@ private void createFilesForTestCopyDirectory(final File grandParentDir, final Fi
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);
}
@@ -390,6 +398,17 @@ public void test_openOutputStream_existsButIsDirectory() {
assertThrows(IllegalArgumentException.class, () -> FileUtils.openOutputStream(directory));
}
+ @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 void testCopyDirectoryPreserveDates() throws Exception {
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 void testCopyDirectoryToChild() throws Exception {
// 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 void testDeleteDirectoryWithNonDirectory() throws Exception {
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 void testDeleteQuietlyDir() throws IOException {
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 void testReadFileToByteArray() throws Exception {
assertEquals(31, data[2]);
}
+
@Test
public void testReadFileToStringWithDefaultEncoding() throws Exception {
final File file = new File(tempDirFile, "read.obj");
@@ -2440,7 +2460,6 @@ public void testReadFileToStringWithDefaultEncoding() throws Exception {
assertEquals("Hello /u1234", data);
}
-
@Test
public void testReadFileToStringWithEncoding() throws Exception {
final File file = new File(tempDirFile, "read.obj");
@@ -2872,6 +2891,7 @@ public void testWriteLines_3argsWithAppendOptionFalse_ShouldDeletePreviousFileLi
assertEquals(expected, actual);
}
+
@Test
public void testWriteLines_3argsWithAppendOptionTrue_ShouldNotDeletePreviousFileLines() throws Exception {
final File file = TestUtils.newFile(tempDirFile, "lines.txt");
@@ -2888,7 +2908,6 @@ public void testWriteLines_3argsWithAppendOptionTrue_ShouldNotDeletePreviousFile
assertEquals(expected, actual);
}
-
@Test
public void testWriteLines_4arg() throws Exception {
final Object[] data = {
@@ -3046,34 +3065,29 @@ public void testWriteStringToFile_WithAppendOptionTrue_ShouldNotDeletePreviousFi
}
@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);
}
@@ -3102,6 +3116,22 @@ public void testWriteStringToFileWithEncoding_WithAppendOptionTrue_ShouldNotDele
assertEquals(expected, actual);
}
+ @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");

MODIFY
src/test/java/org/apache/commons/io/file/PathUtilsTest.java
src/test/java/org/apache/commons/io/file/PathUtilsTest.java
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;
@@ -183,7 +184,7 @@ public void testCreateDirectoriesNew() throws IOException {
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 void testNewOutputStreamNewFileAppendTrue() throws IOException {
public void testNewOutputStreamNewFileInsideExistingSymlinkedDir() 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
- public void testNewOutputStreamNewFileInsideExistingSymlinkedDirFollow() throws IOException {
- final Path symlinkDir = createTempSymlinkedRelativeDir();
- final Path file = symlinkDir.resolve("test.txt");
- assertThrowsExactly(FileAlreadyExistsException.class, () -> PathUtils.newOutputStream(file, false));
}
@Test

Restore some behavior based on findings described in
https://github.com/apache/commons-io/pull/324