This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-clean-plugin.git

commit b5b7cb00e7ee015751764fb3099d534c3d741d39
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Mon Mar 31 17:07:23 2025 +0200

    Try to port MCLEAN-93: Windows NTFS junctions support.
---
 .../org/apache/maven/plugins/clean/Cleaner.java    | 48 ++++++++++++++++++----
 1 file changed, 39 insertions(+), 9 deletions(-)

diff --git a/src/main/java/org/apache/maven/plugins/clean/Cleaner.java 
b/src/main/java/org/apache/maven/plugins/clean/Cleaner.java
index ffac936..624ef47 100644
--- a/src/main/java/org/apache/maven/plugins/clean/Cleaner.java
+++ b/src/main/java/org/apache/maven/plugins/clean/Cleaner.java
@@ -49,7 +49,9 @@ import org.apache.maven.api.plugin.Log;
  * @author Martin Desruisseaux
  */
 final class Cleaner implements FileVisitor<Path> {
-
+    /**
+     * Whether the host operating system is from the Windows family.
+     */
     private static final boolean ON_WINDOWS = (File.separatorChar == '\\');
 
     private static final SessionData.Key<Path> LAST_DIRECTORY_TO_DELETE =
@@ -193,7 +195,7 @@ final class Cleaner implements FileVisitor<Path> {
         var options = EnumSet.noneOf(FileVisitOption.class);
         if (followSymlinks) {
             options.add(FileVisitOption.FOLLOW_LINKS);
-            basedir = getCanonicalPath(basedir);
+            basedir = getCanonicalPath(basedir, null);
         }
         if (selector == null && !followSymlinks && fastDir != null && session 
!= null) {
             // If anything wrong happens, we'll just use the usual deletion 
mechanism
@@ -275,12 +277,21 @@ final class Cleaner implements FileVisitor<Path> {
      */
     @Override
     public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) 
throws IOException {
-        if ((selector == null || selector.matches(file)) && tryDelete(file)) {
-            if (listDeletedFiles) {
-                logDelete(file, attrs);
-            }
+        if (ON_WINDOWS && followSymlinks && attrs.isDirectory() && 
attrs.isOther()) {
+            /*
+             * MCLEAN-93: NTFS junctions have isDirectory() and isOther() 
attributes set.
+             * Handle as a directory walked by a new `FileVisitor`.
+             */
+            file = getCanonicalPath(file, null);
+            Files.walkFileTree(file, EnumSet.of(FileVisitOption.FOLLOW_LINKS), 
Integer.MAX_VALUE, this);
         } else {
-            nonEmptyDirectoryLevels.set(currentDepth); // Remember that the 
directory will not be empty.
+            if ((selector == null || selector.matches(file)) && 
tryDelete(file)) {
+                if (listDeletedFiles) {
+                    logDelete(file, attrs);
+                }
+            } else {
+                nonEmptyDirectoryLevels.set(currentDepth); // Remember that 
the directory will not be empty.
+            }
         }
         return FileVisitResult.CONTINUE;
     }
@@ -333,11 +344,30 @@ final class Cleaner implements FileVisitor<Path> {
         return FileVisitResult.CONTINUE;
     }
 
-    private static Path getCanonicalPath(Path path) {
+    /**
+     * Returns the real path of the given file. If the real path cannot be 
obtained,
+     * this method tries to get the real path of the parent and to append the 
rest of
+     * the filename.
+     *
+     * @param  path       the path to get as a canonical path
+     * @param  mainError  should be {@code null} (reserved to recursive calls 
of this method)
+     * @return the real path of the given path
+     * @throws IOException if the canonical path cannot be obtained
+     */
+    private static Path getCanonicalPath(final Path path, IOException 
mainError) throws IOException {
         try {
             return path.toRealPath();
         } catch (IOException e) {
-            return 
getCanonicalPath(path.getParent()).resolve(path.getFileName());
+            if (mainError == null) {
+                mainError = e;
+            } else {
+                mainError.addSuppressed(e);
+            }
+            final Path parent = path.getParent();
+            if (parent != null) {
+                return getCanonicalPath(parent, 
mainError).resolve(path.getFileName());
+            }
+            throw e;
         }
     }
 

Reply via email to