You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by bo...@apache.org on 2008/09/04 17:44:26 UTC

svn commit: r692115 - in /ant/core/trunk: WHATSNEW src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java src/tests/antunit/taskdefs/optional/unix/symlink-test.xml

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>