All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tools.ant.util.SymbolicLinkUtils Maven / Gradle / Ivy

There is a newer version: 1.0.b11
Show newest version
/*
 *  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.
 *
 */
package org.apache.tools.ant.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Execute;

/**
 * Contains methods related to symbolic links - or what Ant thinks is
 * a symbolic link based on the absent support for them in Java.
 *
 * @since Ant 1.8.0
 */
public class SymbolicLinkUtils {
    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();

    /**
     * Shared instance.
     */
    private static final SymbolicLinkUtils PRIMARY_INSTANCE =
        new SymbolicLinkUtils();

    /**
     * Method to retrieve The SymbolicLinkUtils, which is shared by
     * all users of this method.
     * @return an instance of SymbolicLinkUtils.
     */
    public static SymbolicLinkUtils getSymbolicLinkUtils() {
        // keep the door open for Java X.Y specific subclass if symbolic
        // links ever become supported in the classlib
        return PRIMARY_INSTANCE;
    }

    /**
     * Empty constructor.
     */
    protected SymbolicLinkUtils() {
    }

    /**
     * Checks whether a given file is a symbolic link.
     *
     * 

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.

* * @param file the file to test. Must not be null. * * @return true if the file is a symbolic link. * @throws IOException on error. */ public boolean isSymbolicLink(File file) throws IOException { return isSymbolicLink(file.getParentFile(), file.getName()); } /** * Checks whether a given file is a symbolic link. * *

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.

* * @param name the name of the file to test. * * @return true if the file is a symbolic link. * @throws IOException on error. */ public boolean isSymbolicLink(String name) throws IOException { return isSymbolicLink(new File(name)); } /** * Checks whether a given file is a symbolic link. * *

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.

* * @param parent the parent directory of the file to test * @param name the name of the file to test. * * @return true if the file is a symbolic link. * @throws IOException on error. */ public boolean isSymbolicLink(File parent, String name) throws IOException { File toTest = parent != null ? new File(parent.getCanonicalPath(), name) : new File(name); return !toTest.getAbsolutePath().equals(toTest.getCanonicalPath()); } /** * Checks whether a given file is a broken symbolic link. * *

It doesn't really test for symbolic links but whether Java * reports that the File doesn't exist but its parent's child list * contains it--this may lead to false positives on some * platforms.

* *

Note that #isSymbolicLink returns false if this method * returns true since Java won't produce a canonical name * different from the abolute one if the link is broken.

* * @param name the name of the file to test. * * @return true if the file is a broken symbolic link. * @throws IOException on error. */ public boolean isDanglingSymbolicLink(String name) throws IOException { return isDanglingSymbolicLink(new File(name)); } /** * Checks whether a given file is a broken symbolic link. * *

It doesn't really test for symbolic links but whether Java * reports that the File doesn't exist but its parent's child list * contains it--this may lead to false positives on some * platforms.

* *

Note that #isSymbolicLink returns false if this method * returns true since Java won't produce a canonical name * different from the abolute one if the link is broken.

* * @param file the file to test. * * @return true if the file is a broken symbolic link. * @throws IOException on error. */ public boolean isDanglingSymbolicLink(File file) throws IOException { return isDanglingSymbolicLink(file.getParentFile(), file.getName()); } /** * Checks whether a given file is a broken symbolic link. * *

It doesn't really test for symbolic links but whether Java * reports that the File doesn't exist but its parent's child list * contains it--this may lead to false positives on some * platforms.

* *

Note that #isSymbolicLink returns false if this method * returns true since Java won't produce a canonical name * different from the abolute one if the link is broken.

* * @param parent the parent directory of the file to test * @param name the name of the file to test. * * @return true if the file is a broken symbolic link. * @throws IOException on error. */ public boolean isDanglingSymbolicLink(File parent, String name) throws IOException { File f = new File(parent, name); if (!f.exists()) { final String localName = f.getName(); String[] c = parent.list(new FilenameFilter() { public boolean accept(File d, String n) { return localName.equals(n); } }); return c != null && c.length > 0; } return false; } /** * Delete a symlink (without deleting the associated resource). * *

This is a utility method that removes a unix symlink without * removing the resource that the symlink points to. If it is * accidentally invoked on a real file, the real file will not be * harmed, but silently ignored.

* *

Normaly this method works by * getting the canonical path of the link, using the canonical path to * rename the resource (breaking the link) and then deleting the link. * The resource is then returned to its original name inside a finally * block to ensure that the resource is unharmed even in the event of * an exception.

* *

There may be cases where the algorithm described above doesn't work, * in that case the method tries to use the native "rm" command on * the symlink instead.

* * @param link A File object of the symlink to delete. * @param task An Ant Task required if "rm" needs to be invoked. * * @throws IOException If calls to File.rename, * File.delete or File.getCanonicalPath * fail. * @throws BuildException if the execution of "rm" failed. */ public void deleteSymbolicLink(File link, Task task) throws IOException { if (isDanglingSymbolicLink(link)) { if (!link.delete()) { throw new IOException("failed to remove dangling symbolic link " + link); } return; } if (!isSymbolicLink(link)) { // plain file, not a link return; } if (!link.exists()) { throw new FileNotFoundException("No such symbolic link: " + link); } // find the resource of the existing link: File target = link.getCanonicalFile(); // no reason to try the renaming algorithm if we aren't allowed to // write to the target's parent directory. Let's hope that // File.canWrite works on all platforms. if (task == null || target.getParentFile().canWrite()) { // rename the resource, thus breaking the link: File temp = FILE_UTILS.createTempFile("symlink", ".tmp", target.getParentFile(), false, false); if (FILE_UTILS.isLeadingPath(target, link)) { // link points to a parent directory, renaming the parent // will rename the file link = new File(temp, FILE_UTILS.removeLeadingPath(target, link)); } boolean renamedTarget = false; try { try { FILE_UTILS.rename(target, temp); renamedTarget = true; } catch (IOException e) { throw new IOException("Couldn't rename resource when " + "attempting to delete '" + link + "'. Reason: " + e.getMessage()); } // delete the (now) broken link: if (!link.delete()) { throw new IOException("Couldn't delete symlink: " + link + " (was it a real file? is this " + "not a UNIX system?)"); } } finally { if (renamedTarget) { // return the resource to its original name: try { FILE_UTILS.rename(temp, target); } catch (IOException e) { throw new IOException("Couldn't return resource " + temp + " to its original name: " + target.getAbsolutePath() + ". Reason: " + e.getMessage() + "\n THE RESOURCE'S NAME ON DISK" + " HAS BEEN CHANGED BY THIS" + " ERROR!\n"); } } } } else { Execute.runCommand(task, new String[] {"rm", link.getAbsolutePath()}); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy