On 19 June 2015 at 19:00, <krosenv...@apache.org> wrote: > Author: krosenvold > Date: Fri Jun 19 18:00:44 2015 > New Revision: 1686472 > > URL: http://svn.apache.org/r1686472 > Log: > IO-452 broken symlink support > > Patch by David Standish. > > Also added reflection-based java7 symlink support from maven code (original > author is me) > > Added: > > commons/proper/io/trunk/src/main/java/org/apache/commons/io/Java7Support.java > Modified: > commons/proper/io/trunk/src/main/java/org/apache/commons/io/FileUtils.java > > commons/proper/io/trunk/src/test/java/org/apache/commons/io/FileUtilsCleanSymlinksTestCase.java > > Modified: > commons/proper/io/trunk/src/main/java/org/apache/commons/io/FileUtils.java > URL: > http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/FileUtils.java?rev=1686472&r1=1686471&r2=1686472&view=diff > ============================================================================== > --- > commons/proper/io/trunk/src/main/java/org/apache/commons/io/FileUtils.java > (original) > +++ > commons/proper/io/trunk/src/main/java/org/apache/commons/io/FileUtils.java > Fri Jun 19 18:00:44 2015 > @@ -3009,8 +3009,10 @@ public class FileUtils { > * Will not return true if there is a Symbolic Link anywhere in the path, > * only if the specific file is. > * <p/> > - * <b>Note:</b> the current implementation always returns {@code false} > if the system > - * is detected as Windows using {@link FilenameUtils#isSystemWindows()} > + * When using jdk1.7, this method delegates to {@code boolean > java.nio.file.Files.isSymbolicLink(Path path)} > + * > + * <b>Note:</b> the current implementation always returns {@code false} > if running on > + * jkd1.6 and the system is detected as Windows using {@link > FilenameUtils#isSystemWindows()} > * <p/> > * For code that runs on Java 1.7 or later, use the following method > instead: > * <br> > @@ -3021,6 +3023,11 @@ public class FileUtils { > * @since 2.0 > */ > public static boolean isSymlink(final File file) throws IOException { > + if ( Java7Support.isAtLeastJava7() ) > + { > + return Java7Support.isSymLink( file ); > + } > + > if (file == null) { > throw new NullPointerException("File must not be null"); > } > @@ -3036,10 +3043,41 @@ public class FileUtils { > } > > if > (fileInCanonicalDir.getCanonicalFile().equals(fileInCanonicalDir.getAbsoluteFile())) > { > - return false; > + return isBrokenSymlink(file); > } else { > return true; > } > } > > + /** > + * Determines if the specified file is possibly a broken symbolic link. > + * > + * @param file the file to check > + > + * @return true if the file is a Symbolic Link > + * @throws IOException if an IO error occurs while checking the file > + */ > + private static boolean isBrokenSymlink(final File file) throws > IOException { > + // if file exists then if it is a symlink it's not broken > + if (file.exists()) { > + return false; > + } > + // a broken symlink will show up in the list of files of its parent > directory > + final File canon = file.getCanonicalFile(); > + File parentDir = canon.getParentFile(); > + if (parentDir == null || !parentDir.exists()) { > + return false; > + } > + > + // is it worthwhile to create a FileFilterUtil method for this? > + // is it worthwhile to create an "identity" IOFileFilter for this? > + File[] fileInDir = parentDir.listFiles( > + new FileFilter() { > + public boolean accept(File aFile) { > + return aFile.equals(canon); > + } > + } > + ); > + return fileInDir.length > 0; > + } > } > > Added: > commons/proper/io/trunk/src/main/java/org/apache/commons/io/Java7Support.java > URL: > http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/Java7Support.java?rev=1686472&view=auto > ============================================================================== > --- > commons/proper/io/trunk/src/main/java/org/apache/commons/io/Java7Support.java > (added) > +++ > commons/proper/io/trunk/src/main/java/org/apache/commons/io/Java7Support.java > Fri Jun 19 18:00:44 2015 > @@ -0,0 +1,199 @@ > +package org.apache.commons.io; > + > +/* > + * Licensed to the Apache Software Foundation (ASF) under one > + * or more contributor license agreements. See the NOTICE file > + * distributed with this work for additional information > + * regarding copyright ownership. The ASF licenses this file > + * to you under the Apache License, Version 2.0 (the > + * "License"); you may not use this file except in compliance > + * with the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, > + * software distributed under the License is distributed on an > + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY > + * KIND, either express or implied. See the License for the > + * specific language governing permissions and limitations > + * under the License. > + */ > + > +import java.io.File; > +import java.io.IOException; > +import java.lang.reflect.Array; > +import java.lang.reflect.InvocationTargetException; > +import java.lang.reflect.Method; > + > +/** > + * Java7 feature detection and reflection based feature access. > + * > + * Taken from maven-shared-utils, only for private usage until we go full > java7 > + */ > +class Java7Support > +{ > + > + private static final boolean IS_JAVA7; > + > + private static Method isSymbolicLink; > + > + private static Method delete; > + > + 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;
The above should all be final, as for IS_JAVA7 > + > + static > + { > + boolean isJava7x = true; > + try > + { > + ClassLoader cl = Thread.currentThread().getContextClassLoader(); > + Class<?> files = cl.loadClass( "java.nio.file.Files" ); > + Class<?> path = cl.loadClass( "java.nio.file.Path" ); > + Class<?> fa = cl.loadClass( > "java.nio.file.attribute.FileAttribute" ); > + Class<?> linkOption = cl.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; There seems to be no need to create object o. > + 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 ) > + { > + isJava7x = false; > + } > + catch ( NoSuchMethodException e ) > + { > + isJava7x = false; > + } > + IS_JAVA7 = isJava7x; > + } > + > + public static boolean isSymLink( File file ) > + { > + try > + { > + Object path = toPath.invoke( file ); > + return (Boolean) isSymbolicLink.invoke( null, path ); The Boolean should be explicitly converted to boolean. > + } > + catch ( IllegalAccessException e ) > + { > + throw new RuntimeException( e ); > + } > + catch ( InvocationTargetException e ) > + { > + throw new RuntimeException( e ); > + } > + } > + > + > + public static File readSymbolicLink( 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( File file ) > + throws IOException > + { > + try > + { > + Object path = toPath.invoke( file ); > + final Object invoke = exists.invoke( null, path, emptyLinkOpts ); > + return (Boolean) invoke; Same here, use an explicit cast. > + } > + catch ( IllegalAccessException e ) > + { > + throw new RuntimeException( e ); > + } > + catch ( InvocationTargetException e ) > + { > + throw (RuntimeException) e.getTargetException(); > + } > + > + } > + > + public static File createSymbolicLink( File symlink, 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 > + * @throws IOException > + */ > + public static void delete( File file ) > + throws IOException > + { > + try > + { > + Object path = toPath.invoke( file ); > + delete.invoke( null, path ); > + } > + catch ( IllegalAccessException e ) > + { > + throw new RuntimeException( e ); > + } > + catch ( InvocationTargetException e ) > + { > + throw (IOException) e.getTargetException(); > + } > + } > + > + public static boolean isAtLeastJava7() > + { > + return IS_JAVA7; > + } > + > +} > > Modified: > commons/proper/io/trunk/src/test/java/org/apache/commons/io/FileUtilsCleanSymlinksTestCase.java > URL: > http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/FileUtilsCleanSymlinksTestCase.java?rev=1686472&r1=1686471&r2=1686472&view=diff > ============================================================================== > --- > commons/proper/io/trunk/src/test/java/org/apache/commons/io/FileUtilsCleanSymlinksTestCase.java > (original) > +++ > commons/proper/io/trunk/src/test/java/org/apache/commons/io/FileUtilsCleanSymlinksTestCase.java > Fri Jun 19 18:00:44 2015 > @@ -203,6 +203,25 @@ public class FileUtilsCleanSymlinksTestC > assertFalse(FileUtils.isSymlink(randomFile)); > } > > + public void testIdentifiesBrokenSymlinkFile() throws Exception { > + if (System.getProperty("os.name").startsWith("Win")) { > + // cant create symlinks in windows. > + return; > + } > + > + final File noexistFile = new File(top, "noexist"); > + final File symlinkFile = new File(top, "fakeinner"); > + final File badSymlinkInPathFile = new File(symlinkFile, "fakeinner"); > + final File noexistParentFile = new File("noexist", "file"); > + > + setupSymlink(noexistFile, symlinkFile); > + > + assertTrue(FileUtils.isSymlink(symlinkFile)); > + assertFalse(FileUtils.isSymlink(noexistFile)); > + assertFalse(FileUtils.isSymlink(noexistParentFile)); > + assertFalse(FileUtils.isSymlink(badSymlinkInPathFile)); > + } > + > public void testCorrectlyIdentifySymlinkWithParentSymLink() throws > Exception { > if (System.getProperty("os.name").startsWith("Win")) { > // cant create symlinks in windows. > > --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org