aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SymbolicLinkUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SymbolicLinkUtils.java')
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SymbolicLinkUtils.java296
1 files changed, 296 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SymbolicLinkUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SymbolicLinkUtils.java
new file mode 100644
index 00000000..3bc9918e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SymbolicLinkUtils.java
@@ -0,0 +1,296 @@
+/*
+ * 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.BuildException;
+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.
+ *
+ * <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 test. Must not be null.
+ *
+ * @return true if the file is a symbolic link.
+ * @throws IOException on error.
+ */
+ public boolean isSymbolicLink(final File file) throws IOException {
+ return isSymbolicLink(file.getParentFile(), file.getName());
+ }
+
+ /**
+ * 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.</p>
+ *
+ * @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(final String name) throws IOException {
+ return isSymbolicLink(new File(name));
+ }
+
+ /**
+ * 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.</p>
+ *
+ * @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(final File parent, final String name)
+ throws IOException {
+ final 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.
+ *
+ * <p>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.</p>
+ *
+ * <p>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.</p>
+ *
+ * @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(final String name) throws IOException {
+ return isDanglingSymbolicLink(new File(name));
+ }
+
+ /**
+ * Checks whether a given file is a broken symbolic link.
+ *
+ * <p>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.</p>
+ *
+ * <p>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.</p>
+ *
+ * @param file the file to test.
+ *
+ * @return true if the file is a broken symbolic link.
+ * @throws IOException on error.
+ */
+ public boolean isDanglingSymbolicLink(final File file) throws IOException {
+ return isDanglingSymbolicLink(file.getParentFile(), file.getName());
+ }
+
+ /**
+ * Checks whether a given file is a broken symbolic link.
+ *
+ * <p>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.</p>
+ *
+ * <p>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.</p>
+ *
+ * @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(final File parent, final String name)
+ throws IOException {
+ final File f = new File(parent, name);
+ if (!f.exists()) {
+ final String localName = f.getName();
+ final String[] c = parent.list(new FilenameFilter() {
+ public boolean accept(final File d, final String n) {
+ return localName.equals(n);
+ }
+ });
+ return c != null && c.length > 0;
+ }
+ return false;
+ }
+
+ /**
+ * Delete a symlink (without deleting the associated resource).
+ *
+ * <p>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.</p>
+ *
+ * <p>Normally 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.</p>
+ *
+ * <p>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.</p>
+ *
+ * @param link A <code>File</code> object of the symlink to delete.
+ * @param task An Ant Task required if "rm" needs to be invoked.
+ *
+ * @throws IOException If calls to <code>File.rename</code>,
+ * <code>File.delete</code> or <code>File.getCanonicalPath</code>
+ * fail.
+ * @throws BuildException if the execution of "rm" failed.
+ */
+ public void deleteSymbolicLink(File link, final 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:
+ final 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:
+ final 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 (final 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 (final 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()});
+ }
+ }
+
+}