Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 29 additions & 20 deletions src/main/java/org/codehaus/plexus/util/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
Expand Down Expand Up @@ -1176,45 +1177,53 @@
if (file.isDirectory()) {
deleteDirectory(file);
} else {
/*
* NOTE: Always try to delete the file even if it appears to be non-existent. This will ensure that a
* symlink whose target does not exist is deleted, too.
*/
boolean filePresent = file.getCanonicalFile().exists();
if (!deleteFile(file) && filePresent) {
final String message = "File " + file + " unable to be deleted.";
throw new IOException(message);
if (!deleteFile(file)) {
throw new IOException("File " + file + " unable to be deleted.");
}
}
}

/**
* Accommodate Windows bug encountered in both Sun and IBM JDKs. Others possible. If the delete does not work, call
* Deletes a file, or a symlink without following it. A file that does not exist (including a dangling symlink,
* which {@link Files#deleteIfExists} removes) counts as deleted and returns immediately. Only if the file still
* exists after a failed attempt, accommodate the Windows bug encountered in both Sun and IBM JDKs: call
* System.gc(), wait a little and try again.
*
* @param file a file
* @return {@code true} if the file no longer exists
* @throws IOException if any
*/
private static boolean deleteFile(File file) throws IOException {
if (file.isDirectory()) {
throw new IOException("File " + file + " isn't a file.");
}

if (!file.delete()) {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
file = file.getCanonicalFile();
System.gc();
final Path path = file.toPath();
try {
Files.deleteIfExists(path);
return true;
} catch (IOException e) {
if (!Files.exists(path, LinkOption.NOFOLLOW_LINKS)) {
return true;
}
}

try {
Thread.sleep(10);
return file.delete();
} catch (InterruptedException ignore) {
return file.delete();
}
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
System.gc();
}

return true;
try {
Thread.sleep(10);
} catch (InterruptedException ignore) {
Thread.currentThread().interrupt();
}

try {
Files.deleteIfExists(path);
return true;
} catch (IOException e) {
return !Files.exists(path, LinkOption.NOFOLLOW_LINKS);
}
}

/**
Expand Down Expand Up @@ -1928,9 +1937,9 @@
fileReader = null;
} finally {
//noinspection deprecation
IOUtil.close(fileReader);

Check warning on line 1940 in src/main/java/org/codehaus/plexus/util/FileUtils.java

View workflow job for this annotation

GitHub Actions / Build it / Verify / ubuntu-26.04 jdk-25-zulu 3.10.0

close(java.io.Reader) in org.codehaus.plexus.util.IOUtil has been deprecated

Check warning on line 1940 in src/main/java/org/codehaus/plexus/util/FileUtils.java

View workflow job for this annotation

GitHub Actions / Build it / Verify / macos-latest jdk-25-zulu 3.10.0

close(java.io.Reader) in org.codehaus.plexus.util.IOUtil has been deprecated

Check warning on line 1940 in src/main/java/org/codehaus/plexus/util/FileUtils.java

View workflow job for this annotation

GitHub Actions / Build it / Verify / ubuntu-latest jdk-8-zulu 3.10.0

close(java.io.Reader) in org.codehaus.plexus.util.IOUtil has been deprecated

Check warning on line 1940 in src/main/java/org/codehaus/plexus/util/FileUtils.java

View workflow job for this annotation

GitHub Actions / Build it / Verify / ubuntu-latest jdk-21-zulu 3.10.0

close(java.io.Reader) in org.codehaus.plexus.util.IOUtil has been deprecated

Check warning on line 1940 in src/main/java/org/codehaus/plexus/util/FileUtils.java

View workflow job for this annotation

GitHub Actions / Build it / Verify / ubuntu-latest jdk-25-zulu 3.10.0

close(java.io.Reader) in org.codehaus.plexus.util.IOUtil has been deprecated
//noinspection deprecation
IOUtil.close(fileWriter);

Check warning on line 1942 in src/main/java/org/codehaus/plexus/util/FileUtils.java

View workflow job for this annotation

GitHub Actions / Build it / Verify / ubuntu-26.04 jdk-25-zulu 3.10.0

close(java.io.Writer) in org.codehaus.plexus.util.IOUtil has been deprecated

Check warning on line 1942 in src/main/java/org/codehaus/plexus/util/FileUtils.java

View workflow job for this annotation

GitHub Actions / Build it / Verify / macos-latest jdk-25-zulu 3.10.0

close(java.io.Writer) in org.codehaus.plexus.util.IOUtil has been deprecated

Check warning on line 1942 in src/main/java/org/codehaus/plexus/util/FileUtils.java

View workflow job for this annotation

GitHub Actions / Build it / Verify / ubuntu-latest jdk-8-zulu 3.10.0

close(java.io.Writer) in org.codehaus.plexus.util.IOUtil has been deprecated

Check warning on line 1942 in src/main/java/org/codehaus/plexus/util/FileUtils.java

View workflow job for this annotation

GitHub Actions / Build it / Verify / ubuntu-latest jdk-21-zulu 3.10.0

close(java.io.Writer) in org.codehaus.plexus.util.IOUtil has been deprecated

Check warning on line 1942 in src/main/java/org/codehaus/plexus/util/FileUtils.java

View workflow job for this annotation

GitHub Actions / Build it / Verify / ubuntu-latest jdk-25-zulu 3.10.0

close(java.io.Writer) in org.codehaus.plexus.util.IOUtil has been deprecated
}
} else {
if (isSourceNewerThanDestination(from, to) || overwrite) {
Expand Down
22 changes: 22 additions & 0 deletions src/test/java/org/codehaus/plexus/util/FileUtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,28 @@ void forceDeleteAFile2() throws Exception {
assertFalse(destination.exists(), "Check No Exist");
}

@Test
void forceDeleteNonExistingFile() throws Exception {
final File missing = new File(getTestDirectory(), "does-not-exist.txt");
assertFalse(missing.exists());
FileUtils.forceDelete(missing);
assertFalse(missing.exists());
}

@Test
void forceDeleteDanglingSymlink() throws Exception {
final File target = new File(getTestDirectory(), "dangling-target.txt");
final File symlink = new File(getTestDirectory(), "dangling-link");
createFile(target, 1);
createSymlink(symlink, target);
assumeTrue(Files.isSymbolicLink(symlink.toPath()), "the platform created a real symlink");
assertTrue(target.delete());
// Windows stops reporting a file link as a symlink once its target is gone
assumeTrue(Files.isSymbolicLink(symlink.toPath()), "the platform keeps a dangling symlink");
FileUtils.forceDelete(symlink);
assertFalse(Files.isSymbolicLink(symlink.toPath()), "Dangling symlink should be removed");
}

@Test
void copyFile1ToDir() throws Exception {
final File directory = new File(getTestDirectory(), "subdir");
Expand Down
Loading