On 19 June 2015 at 19:00, <[email protected]> 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: [email protected]
For additional commands, e-mail: [email protected]