FileUtils.forceDelete does not delete invalid links. Testcase and fix
MODIFY
src/main/java/org/apache/commons/io/file/DeletingPathVisitor.java
src/main/java/org/apache/commons/io/file/DeletingPathVisitor.java
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.LinkOption;
+import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
@@ -150,12 +151,24 @@ public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttribut
@Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
- if (accept(file) && Files.exists(file, linkOptions)) {
+ if (accept(file)) {
+ // delete files and valid links, respecting linkOptions
+ if (Files.exists(file, linkOptions)) {
if (overrideReadOnly) {
PathUtils.setReadOnly(file, false, linkOptions);
}
Files.deleteIfExists(file);
}
+ // invalid links will survive previous delete, different approach needed:
+ if (Files.isSymbolicLink(file)) {
+ try {
+ // deleteIfExists does not work for this case
+ Files.delete(file);
+ } catch (NoSuchFileException e) {
+ // ignore
+ }
+ }
+ }
updateFileCounters(file, attrs);
return FileVisitResult.CONTINUE;
}

MODIFY
src/test/java/org/apache/commons/io/FileUtilsDeleteDirectoryBaseTestCase.java
src/test/java/org/apache/commons/io/FileUtilsDeleteDirectoryBaseTestCase.java
@@ -194,6 +194,29 @@ public void testDeleteParentSymlink2() throws Exception {
assertEquals(1, randomDirectory.list().length, "Contents of sym link should not have been removed");
}
+ @Test
+ public void testDeleteInvalidLinks() throws Exception {
+ File aFile = new File(top, "realParentDirA");
+ assertTrue(aFile.mkdir());
+ File bFile = new File(aFile, "realChildDirB");
+ assertTrue(bFile.mkdir());
+
+ File cFile = new File(top, "realParentDirC");
+ assertTrue(cFile.mkdir());
+ File dFile = new File(cFile, "realChildDirD");
+ assertTrue(dFile.mkdir());
+
+ File linkToC = new File(bFile, "linkToC");
+ Files.createSymbolicLink(linkToC.toPath(), cFile.toPath());
+
+ File linkToB = new File(dFile, "linkToB");
+ Files.createSymbolicLink(linkToB.toPath(), bFile.toPath());
+
+ FileUtils.deleteDirectory(aFile);
+ FileUtils.deleteDirectory(cFile);
+ assertEquals(0, top.list().length);
+ }
+
@Test
public void testDeletesNested() throws Exception {
final File nested = new File(top, "nested");

IO-702 FileUtils.forceDelete does not delete invalid links. Testcase and fix (#187)