Browse Source

Move delete method to SymbolicLinkUtils

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@703318 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 16 years ago
parent
commit
24808c7d4b
2 changed files with 123 additions and 137 deletions
  1. +12
    -137
      src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java
  2. +111
    -0
      src/main/org/apache/tools/ant/util/SymbolicLinkUtils.java

+ 12
- 137
src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java View File

@@ -185,7 +185,7 @@ public class Symlink extends DispatchTask {
return;
}
log("Removing symlink: " + link);
deleteSymlink(link, this);
SYMLINK_UTILS.deleteSymbolicLink(new File(link), this);
} catch (FileNotFoundException fnfe) {
handleError(fnfe.toString());
} catch (IOException ioe) {
@@ -219,7 +219,7 @@ public class Symlink extends DispatchTask {
doLink(res, lnk);
} else if (!test.getCanonicalPath().equals(
new File(res).getCanonicalPath())) {
deleteSymlink(lnk, this);
SYMLINK_UTILS.deleteSymbolicLink(test, this);
doLink(res, lnk);
} // else lnk exists, do nothing
} catch (IOException ioe) {
@@ -378,32 +378,13 @@ public class Symlink extends DispatchTask {
* <code>File</code> that doesn't exist.
* @throws IOException If calls to <code>File.rename</code>
* or <code>File.delete</code> fail.
* @deprecated use the two-arg version which also works if the link's
* target can not be renamed.
* @deprecated use
* org.apache.tools.ant.util.SymbolicLinkUtils#deleteSymbolicLink
* instead
*/
public static void deleteSymlink(String path)
throws IOException, FileNotFoundException {
deleteSymlink(new File(path));
}

/**
* Delete a symlink (without deleting the associated resource).
*
* <p>This is a convenience method that simply invokes
* <code>deleteSymlink(java.io.File)</code>.
*
* @param path A string containing the path of the symlink to delete.
* @param task An Ant Task required if "rm" needs to be invoked.
*
* @throws FileNotFoundException When the path results in a
* <code>File</code> that doesn't exist.
* @throws IOException If calls to <code>File.rename</code>
* or <code>File.delete</code> fail.
* @since Ant 1.8.0
*/
public static void deleteSymlink(String path, Task t)
throws IOException, FileNotFoundException {
deleteSymlink(new File(path), t);
SYMLINK_UTILS.deleteSymbolicLink(new File(path), null);
}

/**
@@ -411,8 +392,7 @@ public class Symlink extends DispatchTask {
*
* <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 an exception
* will be thrown when the deletion is attempted.</p>
* on a real file, the real file will not be harmed.</p>
*
* <p>This method works by
* getting the canonical path of the link, using the canonical path to
@@ -431,118 +411,13 @@ public class Symlink extends DispatchTask {
* <code>File.delete</code> or
* <code>File.getCanonicalPath</code>
* fail.
* @deprecated use the two-arg version which also works if the link's
* target can not be renamed.
* @deprecated use
* org.apache.tools.ant.util.SymbolicLinkUtils#deleteSymbolicLink
* instead
*/
public static void deleteSymlink(File linkfil)
throws IOException {
deleteSymlink(linkfil, null);
}

/**
* 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 an exception
* will be thrown when the deletion is attempted.</p>
*
* <p>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.</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 linkfil 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.
* @since Ant 1.8.0
*/
public static void deleteSymlink(File linkfil, Task task)
throws IOException {
if (SYMLINK_UTILS.isDanglingSymbolicLink(linkfil.getParentFile(),
linkfil.getName())) {
linkfil.delete();
return;
}

if (!SYMLINK_UTILS.isSymbolicLink(linkfil.getParentFile(),
linkfil.getName())) {
// plain file, not a link
return;
}

if (!linkfil.exists()) {
throw new FileNotFoundException("No such symlink: " + linkfil);
}

// find the resource of the existing link:
File canfil = linkfil.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 || canfil.getParentFile().canWrite()) {

// rename the resource, thus breaking the link:
File temp = FILE_UTILS.createTempFile("symlink", ".tmp",
canfil.getParentFile(), false,
false);

if (FILE_UTILS.isLeadingPath(canfil, linkfil)) {
// link points to a parent directory, renaming the parent
// will rename the file
linkfil = new File(temp,
FILE_UTILS.removeLeadingPath(canfil,
linkfil));
}

boolean renamedTarget = false;
try {
try {
FILE_UTILS.rename(canfil, temp);
renamedTarget = true;
} catch (IOException e) {
throw new IOException("Couldn't rename resource when "
+ "attempting to delete " + linkfil);
}
// delete the (now) broken link:
if (!linkfil.delete()) {
throw new IOException("Couldn't delete symlink: "
+ linkfil
+ " (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, canfil);
} catch (IOException e) {
throw new IOException("Couldn't return resource "
+ temp
+ " to its original name: "
+ canfil.getAbsolutePath()
+ "\n THE RESOURCE'S NAME ON DISK"
+ " HAS BEEN CHANGED BY THIS"
+ " ERROR!\n");
}
}
}
} else {
Execute.runCommand(task,
new String[] {"rm", linkfil.getAbsolutePath()});
}
SYMLINK_UTILS.deleteSymbolicLink(linkfil, null);
}

/**
@@ -597,7 +472,7 @@ public class Symlink extends DispatchTask {
options += "f";
if (linkfil.exists()) {
try {
deleteSymlink(linkfil);
SYMLINK_UTILS.deleteSymbolicLink(linkfil, this);
} catch (FileNotFoundException fnfe) {
log("Symlink disappeared before it was deleted: " + lnk);
} catch (IOException ioe) {


+ 111
- 0
src/main/org/apache/tools/ant/util/SymbolicLinkUtils.java View File

@@ -18,8 +18,12 @@
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
@@ -179,4 +183,111 @@ public class SymbolicLinkUtils {
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>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.</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, 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()});
}
}

}

Loading…
Cancel
Save