From 1331049054d53ef94674a4966e7000bbf8baf6be Mon Sep 17 00:00:00 2001 From: Stefan Bodewig Date: Thu, 4 Sep 2008 15:44:24 +0000 Subject: [PATCH] fall back to "rm" if target cannot be renamed when deleting a symlink git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@692115 13f79535-47bb-0310-9956-ffa450edef68 --- WHATSNEW | 4 + .../ant/taskdefs/optional/unix/Symlink.java | 73 +++++++++++++++++-- .../taskdefs/optional/unix/symlink-test.xml | 17 +++++ 3 files changed, 87 insertions(+), 7 deletions(-) diff --git a/WHATSNEW b/WHATSNEW index 5f3e810c9..a2ff38c9b 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -200,6 +200,10 @@ Fixed bugs: a parent directory. Bugzilla Report 45743. + * failed if ant lacked permission to rename + the link's target. + Bugzilla Report 41525. + Other changes: -------------- diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java b/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java index 4aceb32b8..e1cc3dc70 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java @@ -47,6 +47,7 @@ import java.util.Properties; import org.apache.tools.ant.Project; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.Task; import org.apache.tools.ant.dispatch.DispatchTask; import org.apache.tools.ant.dispatch.DispatchUtils; import org.apache.tools.ant.taskdefs.Execute; @@ -181,7 +182,7 @@ public class Symlink extends DispatchTask { return; } log("Removing symlink: " + link); - deleteSymlink(link); + deleteSymlink(link, this); } catch (FileNotFoundException fnfe) { handleError(fnfe.toString()); } catch (IOException ioe) { @@ -215,7 +216,7 @@ public class Symlink extends DispatchTask { doLink(res, lnk); } else if (!test.getCanonicalPath().equals( new File(res).getCanonicalPath())) { - deleteSymlink(lnk); + deleteSymlink(lnk, this); doLink(res, lnk); } // else lnk exists, do nothing } catch (IOException ioe) { @@ -380,6 +381,24 @@ public class Symlink extends DispatchTask { deleteSymlink(new File(path)); } + /** + * Delete a symlink (without deleting the associated resource). + * + *

This is a convenience method that simply invokes + * deleteSymlink(java.io.File). + * + * @param path A string containing the path of the symlink to delete. + * + * @throws FileNotFoundException When the path results in a + * File that doesn't exist. + * @throws IOException If calls to File.rename + * or File.delete fail. + */ + public static void deleteSymlink(String path, Task t) + throws IOException, FileNotFoundException { + deleteSymlink(new File(path), t); + } + /** * Delete a symlink (without deleting the associated resource). * @@ -388,17 +407,13 @@ public class Symlink extends DispatchTask { * on a real file, the real file will not be harmed, but an exception * will be thrown when the deletion is attempted.

* - *

Normaly this method works by + *

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.

- * *

Since Ant 1.8.0 this method will try to delete the File object if * it reports it wouldn't exist (as symlinks pointing nowhere usually do). * Prior version would throw a FileNotFoundException in that case.

@@ -409,8 +424,42 @@ public class Symlink extends DispatchTask { * File.delete or * File.getCanonicalPath * fail. + * @deprecated use the two-arg version which also works if the link's + * target can not be renamed. */ public static void deleteSymlink(File linkfil) + throws IOException { + deleteSymlink(linkfil, null); + } + + /** + * 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 an exception + * will be thrown when the deletion is attempted.

+ * + *

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 linkfil 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. + */ + public static void deleteSymlink(File linkfil, Task task) throws IOException { if (!linkfil.exists()) { linkfil.delete(); @@ -420,6 +469,12 @@ public class Symlink extends DispatchTask { // 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, @@ -461,6 +516,10 @@ public class Symlink extends DispatchTask { } } } + } else { + Execute.runCommand(task, + new String[] {"rm", linkfil.getAbsolutePath()}); + } } /** diff --git a/src/tests/antunit/taskdefs/optional/unix/symlink-test.xml b/src/tests/antunit/taskdefs/optional/unix/symlink-test.xml index 91bd1651b..b4986891f 100644 --- a/src/tests/antunit/taskdefs/optional/unix/symlink-test.xml +++ b/src/tests/antunit/taskdefs/optional/unix/symlink-test.xml @@ -25,6 +25,12 @@ + + + + + @@ -75,4 +81,15 @@ + + + + + + + + + +