Author: bodewig Date: Thu Sep 4 08:44:24 2008 New Revision: 692115 URL: http://svn.apache.org/viewvc?rev=692115&view=rev Log: fall back to "rm" if target cannot be renamed when deleting a symlink
Modified: ant/core/trunk/WHATSNEW ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java ant/core/trunk/src/tests/antunit/taskdefs/optional/unix/symlink-test.xml Modified: ant/core/trunk/WHATSNEW URL: http://svn.apache.org/viewvc/ant/core/trunk/WHATSNEW?rev=692115&r1=692114&r2=692115&view=diff ============================================================================== --- ant/core/trunk/WHATSNEW (original) +++ ant/core/trunk/WHATSNEW Thu Sep 4 08:44:24 2008 @@ -200,6 +200,10 @@ a parent directory. Bugzilla Report 45743. + * <symlink action="delete"> failed if ant lacked permission to rename + the link's target. + Bugzilla Report 41525. + Other changes: -------------- Modified: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java URL: http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java?rev=692115&r1=692114&r2=692115&view=diff ============================================================================== --- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java (original) +++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java Thu Sep 4 08:44:24 2008 @@ -47,6 +47,7 @@ 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 @@ return; } log("Removing symlink: " + link); - deleteSymlink(link); + deleteSymlink(link, this); } catch (FileNotFoundException fnfe) { handleError(fnfe.toString()); } catch (IOException ioe) { @@ -215,7 +216,7 @@ 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) { @@ -383,22 +384,36 @@ /** * 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. + * + * @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. + */ + public static void deleteSymlink(String path, Task t) + throws IOException, FileNotFoundException { + deleteSymlink(new File(path), t); + } + + /** + * 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 + * <p>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> - * * <p>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.</p> @@ -409,9 +424,43 @@ * <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. */ 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. + */ + public static void deleteSymlink(File linkfil, Task task) + throws IOException { if (!linkfil.exists()) { linkfil.delete(); return; @@ -420,6 +469,12 @@ // 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 @@ } } } + } else { + Execute.runCommand(task, + new String[] {"rm", linkfil.getAbsolutePath()}); + } } /** Modified: ant/core/trunk/src/tests/antunit/taskdefs/optional/unix/symlink-test.xml URL: http://svn.apache.org/viewvc/ant/core/trunk/src/tests/antunit/taskdefs/optional/unix/symlink-test.xml?rev=692115&r1=692114&r2=692115&view=diff ============================================================================== --- ant/core/trunk/src/tests/antunit/taskdefs/optional/unix/symlink-test.xml (original) +++ ant/core/trunk/src/tests/antunit/taskdefs/optional/unix/symlink-test.xml Thu Sep 4 08:44:24 2008 @@ -25,6 +25,12 @@ </condition> </target> + <target name="tearDown" depends="antunit-base.tearDown" + if="chmod.tmp"> + <chmod dir="${chmod.tmp}" perm="755"/> + <delete dir="${chmod.tmp}"/> + </target> + <target name="os"> <mkdir dir="${output}" /> @@ -75,4 +81,15 @@ <au:assertFileDoesntExist file="${output}/link"/> </target> + <target name="testDeleteWithNoPermissionToRenameTarget" + depends="init" if="unix"> + <!-- must be outside of ${output} or "base" tearDown will fail --> + <property name="chmod.tmp" location="${java.io.tmpdir}/ant-symlink-test"/> + <mkdir dir="${chmod.tmp}/A"/> + <chmod perm="555" dir="${chmod.tmp}"/> + <symlink link="${output}/link" resource="${chmod.tmp}/A"/> + <symlink link="${output}/link" action="delete"/> + <au:assertFileDoesntExist file="${output}/link"/> + </target> + </project>