Skip to content

Commit fbc67f8

Browse files
committed
Rework CoreUtility.deleteContent()
- Do not follow links - Remove read only flag on windows (Java 25+)
1 parent e8a7cec commit fbc67f8

File tree

2 files changed

+134
-21
lines changed

2 files changed

+134
-21
lines changed

ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/util/CoreUtility.java

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import org.eclipse.core.runtime.IPath;
3535
import org.eclipse.core.runtime.IProgressMonitor;
3636
import org.eclipse.core.runtime.Platform;
37-
import org.eclipse.core.runtime.SubMonitor;
3837
import org.eclipse.pde.internal.core.PDECore;
3938

4039
public class CoreUtility {
@@ -125,26 +124,7 @@ public static void deleteContent(File fileToDelete) {
125124
* @param monitor progress monitor for reporting and cancellation, can be <code>null</code>
126125
*/
127126
public static void deleteContent(File fileToDelete, IProgressMonitor monitor) {
128-
// can be symlinks
129-
if (!fileToDelete.exists()) {
130-
fileToDelete.delete();
131-
}
132-
if (fileToDelete.exists()) {
133-
SubMonitor subMon = SubMonitor.convert(monitor, 100);
134-
135-
if (fileToDelete.isDirectory()) {
136-
File[] children = fileToDelete.listFiles();
137-
if (children != null && children.length > 0) {
138-
SubMonitor childMon = SubMonitor.convert(subMon.split(90), children.length);
139-
for (File element : children) {
140-
deleteContent(element, childMon.split(1));
141-
}
142-
}
143-
}
144-
fileToDelete.delete();
145-
146-
subMon.done();
147-
}
127+
DeleteContentWalker.deleteDirectory(fileToDelete.toPath(), monitor);
148128
}
149129

150130
public static boolean jarContainsResource(File file, String resource, boolean directory) {
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2000, 2020 IBM Corporation and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
*******************************************************************************/
12+
package org.eclipse.pde.internal.core.util;
13+
14+
import java.io.IOException;
15+
import java.nio.file.FileVisitResult;
16+
import java.nio.file.FileVisitor;
17+
import java.nio.file.Files;
18+
import java.nio.file.Path;
19+
import java.nio.file.attribute.BasicFileAttributes;
20+
import java.util.Objects;
21+
22+
import org.eclipse.core.runtime.IProgressMonitor;
23+
import org.eclipse.core.runtime.NullProgressMonitor;
24+
import org.eclipse.core.runtime.Platform;
25+
import org.eclipse.core.runtime.SubMonitor;
26+
27+
/**
28+
* Deletes content of a directory recursively.
29+
*/
30+
public class DeleteContentWalker implements FileVisitor<Path> {
31+
32+
/**
33+
* Deletes the given root directory and its content. If the deletion fails
34+
* or is canceled by the user, the method returns silently.
35+
*
36+
* @param root
37+
* The root directory to delete.
38+
* @param monitor
39+
* The monitor to report progress to. Can be null.
40+
*/
41+
public static void deleteDirectory(Path root, IProgressMonitor monitor) {
42+
// if there is no file, no need to proceed
43+
if (root == null || !Files.exists(root)) {
44+
return;
45+
}
46+
47+
IProgressMonitor submonitor = createSubMonitor(root, monitor);
48+
49+
try {
50+
Files.walkFileTree(root, new DeleteContentWalker(root, submonitor));
51+
} catch (IOException e) {
52+
// noting to do
53+
} finally {
54+
submonitor.done();
55+
}
56+
}
57+
58+
private static IProgressMonitor createSubMonitor(Path root, IProgressMonitor monitor) {
59+
IProgressMonitor submonitor;
60+
if (monitor == null || monitor instanceof NullProgressMonitor) {
61+
submonitor = SubMonitor.convert(monitor);
62+
} else {
63+
try (var stream = Files.list(root)) {
64+
// only use the root content for progress. anything else would
65+
// be overkill.
66+
long count = stream.count();
67+
submonitor = SubMonitor.convert(monitor, (int) count);
68+
} catch (IOException e) {
69+
// In case of error, just ignore the monitor;
70+
submonitor = SubMonitor.convert(monitor);
71+
}
72+
}
73+
return submonitor;
74+
}
75+
76+
private final Path root;
77+
private final IProgressMonitor monitor;
78+
79+
private DeleteContentWalker(Path root, IProgressMonitor monitor) {
80+
this.root = root;
81+
this.monitor = monitor;
82+
}
83+
84+
@Override
85+
public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs) throws IOException {
86+
if (Platform.OS.isWindows()) {
87+
Files.setAttribute(path, "dos:readonly", false); //$NON-NLS-1$
88+
}
89+
return resultIfNotCanceled(FileVisitResult.CONTINUE);
90+
}
91+
92+
@Override
93+
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
94+
if (Platform.OS.isWindows()) {
95+
Files.setAttribute(path, "dos:readonly", false); //$NON-NLS-1$
96+
}
97+
Files.deleteIfExists(path);
98+
99+
if (Objects.equals(path.getParent(), root)) {
100+
monitor.worked(1);
101+
}
102+
return resultIfNotCanceled(FileVisitResult.CONTINUE);
103+
}
104+
105+
@Override
106+
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
107+
if (exc != null) {
108+
throw exc;
109+
}
110+
return resultIfNotCanceled(FileVisitResult.CONTINUE);
111+
}
112+
113+
@Override
114+
public FileVisitResult postVisitDirectory(Path path, IOException exc) throws IOException {
115+
Files.deleteIfExists(path);
116+
117+
if (Objects.equals(path.getParent(), root)) {
118+
monitor.worked(1);
119+
}
120+
return resultIfNotCanceled(FileVisitResult.CONTINUE);
121+
}
122+
123+
/**
124+
* Returns the given result if not canceled. If canceled
125+
* {@link FileVisitResult#TERMINATE} is returned.
126+
*/
127+
private FileVisitResult resultIfNotCanceled(FileVisitResult result) {
128+
if (monitor.isCanceled()) {
129+
return FileVisitResult.TERMINATE;
130+
}
131+
return result;
132+
}
133+
}

0 commit comments

Comments
 (0)