Author: krosenvold Date: Mon Oct 13 18:42:21 2014 New Revision: 1631506 URL: http://svn.apache.org/r1631506 Log: Added symbolic link detection logic and java7 symlink methods with reflection
Modified: maven/shared/trunk/maven-shared-utils/src/main/java/org/apache/maven/shared/utils/io/FileUtils.java maven/shared/trunk/maven-shared-utils/src/main/java/org/apache/maven/shared/utils/io/Java7Support.java maven/shared/trunk/maven-shared-utils/src/test/java/org/apache/maven/shared/utils/io/FileUtilsTest.java maven/shared/trunk/maven-shared-utils/src/test/java/org/apache/maven/shared/utils/io/Java7SupportTest.java Modified: maven/shared/trunk/maven-shared-utils/src/main/java/org/apache/maven/shared/utils/io/FileUtils.java URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-shared-utils/src/main/java/org/apache/maven/shared/utils/io/FileUtils.java?rev=1631506&r1=1631505&r2=1631506&view=diff ============================================================================== --- maven/shared/trunk/maven-shared-utils/src/main/java/org/apache/maven/shared/utils/io/FileUtils.java (original) +++ maven/shared/trunk/maven-shared-utils/src/main/java/org/apache/maven/shared/utils/io/FileUtils.java Mon Oct 13 18:42:21 2014 @@ -1988,4 +1988,67 @@ public class FileUtils return true; } + + /** + * Checks whether a given file is a symbolic link. + * + * This only works reliably on java7 and higher. For earlier version we use a highly crappy heuristic + * that mostly does not work. + * <p> + * It doesn't really test for symbolic links but whether the canonical and absolute paths of the file are identical + * - this may lead to false positives on some platforms. + * </p> + * + * @param file the file to check + * + */ + public static boolean isSymbolicLink( final File file ) + throws IOException + { + if ( Java7Support.isJava7() ) + { + return Java7Support.isSymLink( file ); + } + return isSymbolicLinkLegacy( file ); + } + + /** + * Checks whether a given file is a symbolic link. + * + * @param file the file to check + * @return true if and only if we reliably can say this is a symlink. This will + * always return false for java versions prior to 1.7. + * + */ + public static boolean isSymbolicLinkForSure( final File file ) + throws IOException + { + return Java7Support.isJava7() && Java7Support.isSymLink( file ); + } + + /** + * Checks whether a given file is a symbolic link. + * <p> + * It doesn't really test for symbolic links but whether the canonical and absolute + * paths of the file are identical - this may lead to false positives on some platforms. + * + * It also returns true for any file that has been reached via a symbolic link, + * if you decide to traverse into the symlink. + * + * As can be seen from the "return" clause of this method, there is really no + * guarantee of any sort from this method. Small wonder this ever got used for + * anything. + * </p> + * + * @param file the file to check + * @return true if the file is a symbolic link or if we're on some crappy os. + * false if the file is not a symlink or we're not able to detect it. + */ + static boolean isSymbolicLinkLegacy( final File file ) + throws IOException + { + final File canonical = new File( file.getCanonicalPath() ); + return !file.getAbsolutePath().equals( canonical.getPath() ); + } + } Modified: maven/shared/trunk/maven-shared-utils/src/main/java/org/apache/maven/shared/utils/io/Java7Support.java URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-shared-utils/src/main/java/org/apache/maven/shared/utils/io/Java7Support.java?rev=1631506&r1=1631505&r2=1631506&view=diff ============================================================================== --- maven/shared/trunk/maven-shared-utils/src/main/java/org/apache/maven/shared/utils/io/Java7Support.java (original) +++ maven/shared/trunk/maven-shared-utils/src/main/java/org/apache/maven/shared/utils/io/Java7Support.java Mon Oct 13 18:42:21 2014 @@ -19,10 +19,18 @@ package org.apache.maven.shared.utils.io * under the License. */ +import com.sun.org.apache.xalan.internal.xsltc.compiler.sym; + +import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; +import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.nio.file.attribute.FileAttribute; /** * Java7 feature detection @@ -40,6 +48,18 @@ public class Java7Support private static Method toPath; + private static Method exists; + + private static Method toFile; + + private static Method readSymlink; + + private static Method createSymlink; + + private static Object emptyLinkOpts; + + private static Object emptyFileAttributes; + static { boolean isJava7x = true; @@ -47,9 +67,19 @@ public class Java7Support { Class<?> files = Thread.currentThread().getContextClassLoader().loadClass( "java.nio.file.Files" ); Class<?> path = Thread.currentThread().getContextClassLoader().loadClass( "java.nio.file.Path" ); + Class<?> fa = Thread.currentThread().getContextClassLoader().loadClass( "java.nio.file.attribute.FileAttribute" ); + Class<?> linkOption = Thread.currentThread().getContextClassLoader().loadClass( "java.nio.file.LinkOption" ); isSymbolicLink = files.getMethod( "isSymbolicLink", path ); delete = files.getMethod( "delete", path ); + readSymlink = files.getMethod( "readSymbolicLink", path ); + + emptyFileAttributes = Array.newInstance( fa, 0 ); + final Object o = emptyFileAttributes; + createSymlink = files.getMethod( "createSymbolicLink", path,path, o.getClass() ); + emptyLinkOpts = Array.newInstance( linkOption, 0 ); + exists = files.getMethod( "exists", path, emptyLinkOpts.getClass() ); toPath = File.class.getMethod( "toPath" ); + toFile = path.getMethod( "toFile" ); } catch ( ClassNotFoundException e ) { @@ -62,7 +92,7 @@ public class Java7Support IS_JAVA7 = isJava7x; } - public static boolean isSymLink( File file ) + public static boolean isSymLink( @Nonnull File file ) { try { @@ -79,6 +109,70 @@ public class Java7Support } } + + public static @Nonnull File readSymbolicLink( @Nonnull File symlink ) + throws IOException + { + try + { + Object path = toPath.invoke( symlink ); + Object resultPath = readSymlink.invoke( null, path ); + return (File) toFile.invoke( resultPath ); + } + catch ( IllegalAccessException e ) + { + throw new RuntimeException( e ); + } + catch ( InvocationTargetException e ) + { + throw new RuntimeException( e ); + } + } + + + public static boolean exists( @Nonnull File file ) + throws IOException + { + try + { + Object path = toPath.invoke( file ); + final Object invoke = exists.invoke( null, path, emptyLinkOpts ); + return ((Boolean)invoke).booleanValue(); + } + catch ( IllegalAccessException e ) + { + throw new RuntimeException( e ); + } + catch ( InvocationTargetException e ) + { + throw (RuntimeException) e.getTargetException(); + } + + } + + public static @Nonnull File createSymbolicLink( @Nonnull File symlink, @Nonnull File target ) + throws IOException + { + try + { + if (!exists( symlink )){ + Object link = toPath.invoke( symlink ); + Object path = createSymlink.invoke( null, link, toPath.invoke( target ), emptyFileAttributes ); + return (File) toFile.invoke( path ); + } + return symlink; + } + catch ( IllegalAccessException e ) + { + throw new RuntimeException( e ); + } + catch ( InvocationTargetException e ) + { + final Throwable targetException = e.getTargetException(); + throw (IOException)targetException; + } + + } /** * Performs a nio delete * @param file the file to delete Modified: maven/shared/trunk/maven-shared-utils/src/test/java/org/apache/maven/shared/utils/io/FileUtilsTest.java URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-shared-utils/src/test/java/org/apache/maven/shared/utils/io/FileUtilsTest.java?rev=1631506&r1=1631505&r2=1631506&view=diff ============================================================================== --- maven/shared/trunk/maven-shared-utils/src/test/java/org/apache/maven/shared/utils/io/FileUtilsTest.java (original) +++ maven/shared/trunk/maven-shared-utils/src/test/java/org/apache/maven/shared/utils/io/FileUtilsTest.java Mon Oct 13 18:42:21 2014 @@ -1368,6 +1368,24 @@ public class FileUtilsTest } @Test + public void isASymbolicLink() + throws IOException + { + File file = new File( "src/test/resources/symlinks/src/symDir" ); + assertTrue(FileUtils.isSymbolicLink(file )); + assertTrue(FileUtils.isSymbolicLinkLegacy(file )); + } + + @Test + public void notASymbolicLink() + throws IOException + { + File file = new File( "src/test/resources/symlinks/src/" ); + assertFalse(FileUtils.isSymbolicLink(file )); + assertFalse(FileUtils.isSymbolicLinkLegacy(file )); + } + + @Test public void extensionUnixRootPathOnUnix() throws Exception { Modified: maven/shared/trunk/maven-shared-utils/src/test/java/org/apache/maven/shared/utils/io/Java7SupportTest.java URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-shared-utils/src/test/java/org/apache/maven/shared/utils/io/Java7SupportTest.java?rev=1631506&r1=1631505&r2=1631506&view=diff ============================================================================== --- maven/shared/trunk/maven-shared-utils/src/test/java/org/apache/maven/shared/utils/io/Java7SupportTest.java (original) +++ maven/shared/trunk/maven-shared-utils/src/test/java/org/apache/maven/shared/utils/io/Java7SupportTest.java Mon Oct 13 18:42:21 2014 @@ -23,6 +23,7 @@ import java.io.File; import org.junit.Test; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; public class Java7SupportTest @@ -38,4 +39,20 @@ public class Java7SupportTest assertFalse( Java7Support.isSymLink( file ) ); } } + @Test + public void createAndReadSymlink() + throws Exception + { + + File file = new File( "target/fzz" ); + if ( Java7Support.isJava7() ) + { + Java7Support.createSymbolicLink( file, new File("../target") ); + + final File file1 = Java7Support.readSymbolicLink( file ); + assertEquals( "target", file1.getName()); + Java7Support.delete( file ); + } + } + }