Skip to content

Commit

Permalink
Add a comment for the junction, add a unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
gnodet committed Jan 11, 2022
1 parent 0ccab3b commit f3f26d8
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 8 deletions.
9 changes: 5 additions & 4 deletions src/main/java/org/apache/maven/plugins/clean/Cleaner.java
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,9 @@ private Result delete( File file, String pathname, Selector selector, boolean fo
{
if ( selector == null || selector.couldHoldSelected( pathname ) )
{
final boolean isSymlink = isSymbolicLink( file.toPath() );
File canonical = followSymlinks ? file : file.getCanonicalFile();
if ( followSymlinks || !isSymlink )
if ( followSymlinks || !isSymbolicLink( file.toPath() ) )
{
File canonical = followSymlinks ? file : file.getCanonicalFile();
String[] filenames = canonical.list();
if ( filenames != null )
{
Expand Down Expand Up @@ -302,7 +301,9 @@ else if ( file.exists() )
private boolean isSymbolicLink( Path path ) throws IOException
{
BasicFileAttributes attrs = Files.readAttributes( path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS );
return attrs.isSymbolicLink() || ( attrs.isDirectory() && attrs.isOther() );
return attrs.isSymbolicLink()
// MCLEAN-93: NTFS junctions have isDirectory() and isOther() attributes set
|| ( attrs.isDirectory() && attrs.isOther() );
}

/**
Expand Down
114 changes: 110 additions & 4 deletions src/test/java/org/apache/maven/plugins/clean/CleanMojoTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,19 @@
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.testing.AbstractMojoTestCase;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;

import static org.apache.commons.io.FileUtils.copyDirectory;
import static org.codehaus.plexus.util.IOUtil.copy;

/**
* Test the clean mojo.
Expand Down Expand Up @@ -215,9 +222,9 @@ public void testMissingDirectory()
public void testCleanLockedFile()
throws Exception
{
if (!System.getProperty("os.name").toLowerCase().contains("windows"))
if ( !System.getProperty("os.name").toLowerCase().contains("windows") )
{
assertTrue( "Ignored this test on none Windows based systems", true );
assertTrue( "Ignore this test on non Windows based systems", true );
return;
}

Expand Down Expand Up @@ -254,9 +261,9 @@ public void testCleanLockedFile()
public void testCleanLockedFileWithNoError()
throws Exception
{
if (!System.getProperty("os.name").toLowerCase().contains("windows"))
if ( !System.getProperty("os.name").toLowerCase().contains("windows") )
{
assertTrue( "Ignored this test on none Windows based systems", true );
assertTrue( "Ignore this test on non Windows based systems", true );
return;
}

Expand All @@ -283,6 +290,105 @@ public void testCleanLockedFileWithNoError()
}
}

/**
* Test the followLink option with windows junctions
* @throws Exception
*/
public void testFollowLinksWithWindowsJunction()
throws Exception
{
if ( !System.getProperty("os.name").toLowerCase().contains("windows") )
{
assertTrue( "Ignore this test on non Windows based systems", true );
return;
}

testSymlink( ( link, target ) ->
{
Process process = new ProcessBuilder()
.directory( link.getParent().toFile() )
.command( "cmd", "/c", "mklink", "/j", link.getFileName().toString(), target.toString() )
.start();
process.waitFor();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
copy( process.getInputStream(), baos );
copy( process.getErrorStream(), baos );
if ( !Files.exists( link ) )
{
throw new IOException( "Unable to create junction: " + baos );
}
} );
}

/**
* Test the followLink option with sym link
* @throws Exception
*/
public void testFollowLinksWithSymLinkOnPosix()
throws Exception
{
if ( System.getProperty("os.name").toLowerCase().contains("windows") )
{
assertTrue( "Ignore this test on Windows based systems", true );
return;
}

testSymlink( ( link, target ) ->
{
try
{
Files.createSymbolicLink(link, target);
}
catch ( IOException e )
{
throw new IOException( "Unable to create symbolic link", e );
}
} );
}

@FunctionalInterface
interface LinkCreator
{
void createLink( Path link, Path target ) throws Exception;
}

private void testSymlink( LinkCreator linkCreator ) throws Exception
{
Cleaner cleaner = new Cleaner( null, null, false, null, null );
Path testDir = Paths.get( "target/test-classes/unit/test-dir" ).toAbsolutePath();
Path dirWithLnk = testDir.resolve( "dir" );
Path orgDir = testDir.resolve( "org-dir" );
Path jctDir = dirWithLnk.resolve( "jct-dir" );
Path file = orgDir.resolve("file.txt");

// create directories, links and file
Files.createDirectories( dirWithLnk );
Files.createDirectories( orgDir );
Files.write(file, Collections.singleton( "Hello world" ) );
linkCreator.createLink( jctDir, orgDir );
// delete
cleaner.delete( dirWithLnk.toFile(), null, false, true, false );
// verify
assertTrue( Files.exists( file ) );
assertFalse( Files.exists( jctDir ) );
assertTrue( Files.exists( orgDir ) );
assertFalse( Files.exists( dirWithLnk ) );

// create directories, links and file
Files.createDirectories( dirWithLnk );
Files.createDirectories( orgDir );
Files.write(file, Collections.singleton( "Hello world" ) );
linkCreator.createLink( jctDir, orgDir );
// delete
cleaner.delete( dirWithLnk.toFile(), null, true, true, false );
// verify
assertFalse( Files.exists( file ) );
assertFalse( Files.exists( jctDir ) );
assertTrue( Files.exists( orgDir ) );
assertFalse( Files.exists( dirWithLnk ) );
}


/**
* @param dir a dir or a file
* @return true if a file/dir exists, false otherwise
Expand Down

0 comments on commit f3f26d8

Please sign in to comment.