Skip to content

Commit 2bdc6c5

Browse files
committed
Try to port MCLEAN-93: Windows NTFS junctions support (second attempt).
1 parent 26a0ca6 commit 2bdc6c5

File tree

1 file changed

+35
-6
lines changed

1 file changed

+35
-6
lines changed

src/main/java/org/apache/maven/plugins/clean/Cleaner.java

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@
4949
* @author Martin Desruisseaux
5050
*/
5151
final class Cleaner implements FileVisitor<Path> {
52-
52+
/**
53+
* Whether the host operating system is from the Windows family.
54+
*/
5355
private static final boolean ON_WINDOWS = (File.separatorChar == '\\');
5456

5557
private static final SessionData.Key<Path> LAST_DIRECTORY_TO_DELETE =
@@ -171,13 +173,13 @@ public void delete(@Nonnull Fileset fileset) throws IOException {
171173
}
172174

173175
/**
174-
* Deletes the specified directories and its contents.
176+
* Deletes the specified directory and its contents.
175177
* Non-existing directories will be silently ignored.
176178
*
177179
* @param basedir the directory to delete, must not be {@code null}
178180
* @throws IOException if a file/directory could not be deleted and {@code failOnError} is {@code true}
179181
*/
180-
public void delete(Path basedir) throws IOException {
182+
public void delete(@Nonnull Path basedir) throws IOException {
181183
if (!Files.isDirectory(basedir)) {
182184
if (Files.notExists(basedir)) {
183185
if (logger.isDebugEnabled()) {
@@ -193,7 +195,7 @@ public void delete(Path basedir) throws IOException {
193195
var options = EnumSet.noneOf(FileVisitOption.class);
194196
if (followSymlinks) {
195197
options.add(FileVisitOption.FOLLOW_LINKS);
196-
basedir = getCanonicalPath(basedir);
198+
basedir = getCanonicalPath(basedir, null);
197199
}
198200
if (selector == null && !followSymlinks && fastDir != null && session != null) {
199201
// If anything wrong happens, we'll just use the usual deletion mechanism
@@ -259,6 +261,14 @@ private boolean fastDelete(Path baseDir) {
259261
*/
260262
@Override
261263
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
264+
if (ON_WINDOWS && !followSymlinks && attrs.isOther()) {
265+
/*
266+
* MCLEAN-93: NTFS junctions have isDirectory() and isOther() attributes set.
267+
* If not following symbolic links, then it should be handled as a file.
268+
*/
269+
visitFile(dir, attrs);
270+
return FileVisitResult.SKIP_SUBTREE;
271+
}
262272
if (selector == null || selector.couldHoldSelected(dir)) {
263273
nonEmptyDirectoryLevels.clear(++currentDepth);
264274
return FileVisitResult.CONTINUE;
@@ -333,11 +343,30 @@ public FileVisitResult postVisitDirectory(Path dir, IOException failure) throws
333343
return FileVisitResult.CONTINUE;
334344
}
335345

336-
private static Path getCanonicalPath(Path path) {
346+
/**
347+
* Returns the real path of the given file. If the real path cannot be obtained,
348+
* this method tries to get the real path of the parent and to append the rest of
349+
* the filename.
350+
*
351+
* @param path the path to get as a canonical path
352+
* @param mainError should be {@code null} (reserved to recursive calls of this method)
353+
* @return the real path of the given path
354+
* @throws IOException if the canonical path cannot be obtained
355+
*/
356+
private static Path getCanonicalPath(final Path path, IOException mainError) throws IOException {
337357
try {
338358
return path.toRealPath();
339359
} catch (IOException e) {
340-
return getCanonicalPath(path.getParent()).resolve(path.getFileName());
360+
if (mainError == null) {
361+
mainError = e;
362+
} else {
363+
mainError.addSuppressed(e);
364+
}
365+
final Path parent = path.getParent();
366+
if (parent != null) {
367+
return getCanonicalPath(parent, mainError).resolve(path.getFileName());
368+
}
369+
throw e;
341370
}
342371
}
343372

0 commit comments

Comments
 (0)