Browse Source

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
master
Stefan Bodewig 17 years ago
parent
commit
1331049054
3 changed files with 87 additions and 7 deletions
  1. +4
    -0
      WHATSNEW
  2. +66
    -7
      src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java
  3. +17
    -0
      src/tests/antunit/taskdefs/optional/unix/symlink-test.xml

+ 4
- 0
WHATSNEW View File

@@ -200,6 +200,10 @@ Fixed bugs:
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:
--------------



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

@@ -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).
*
* <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).
*
@@ -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.</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,8 +424,42 @@ 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.
*/
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();
@@ -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()});
}
}

/**


+ 17
- 0
src/tests/antunit/taskdefs/optional/unix/symlink-test.xml View File

@@ -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>

Loading…
Cancel
Save