Bug 22632 - Delete follows symbolic links to directories
Summary: Delete follows symbolic links to directories
Status: RESOLVED DUPLICATE of bug 36658
Alias: None
Product: Ant
Classification: Unclassified
Component: Core tasks (show other bugs)
Version: 1.5.3
Hardware: All other
: P3 enhancement (vote)
Target Milestone: ---
Assignee: Ant Notifications List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2003-08-21 19:29 UTC by Brian Compton
Modified: 2008-09-04 06:31 UTC (History)
1 user (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Brian Compton 2003-08-21 19:29:52 UTC
I know this was reported before (#1550 and #13353), but I got bit by this today 
and I'm not sure whether anyone plans on fixing this. #13353 has a status 
of "RESOLVED WONTFIX", but I can't imagine that this can be considered 
resolved. Basically, the fact that this bug exists I can no longer use "<delete 
dir=...>", because I cannot be sure that someone did not go into a directory 
and establish a symbolic link to another directory. The default behavior 
for "<delete dir=...>" should be to not follow symbolic links.
Comment 1 Stefan Bodewig 2003-08-22 14:23:01 UTC
<delete>
  <fileset dir="..." followsymlinks="false"/>
</delete>

should be as good.

The dir attribute (together with the includes and excludes related attributes) of
<delete> have only been retained for backwards compatibility when the support
for nested filesets were added in Ant 1.2.  If we added all new features of
filesets (like symlink handling which was added way after 1.2) to <delete> that
would be cumbersome.

Simply don't use dir, use a nested fileset and gain complete control.
Comment 2 Brian Compton 2003-08-22 16:25:23 UTC
I have already tried your suggested solution, and many others, but have not 
come up with any solution which does what I want. 
Using 'followsymlinks="false"' as an attribute of delete or as an attribute of 
a nested fileset does prevent the files in the symbollically linked directory 
from being deleted, however the symbolic link itself is not deleted and hence 
the directory does not get deleted.

I was expecting and need functionality similar to "rm -rf DIRNAME" which does 
not follow symbolic links, but does delete them. I have not been able to figure 
out any way to do this with the built-in tasks.

I also wanted to mention that it does seem like followsymlinks='false' should 
be the default for the delete task. I work with several other developers who 
have been using ANT for a while, and not one knew about this. If the default 
cannot be changed, then a huge warning should be placed in the doc for the 
delete task.
Comment 3 Antoine Levy-Lambert 2003-08-22 17:10:55 UTC
this works for me :
<project name="delete">
  <mkdir dir="alpha/beta"/>
  <symlink link="alpha/epsilon" resource="beta"/>
  <touch file="alpha/epsilon/epsilon.xml"/>
  <touch file="alpha/alpha.xml"/>
  <delete>
    <fileset dir="alpha" followsymlinks="false">
      <include name="epsilon/**"/>
    </fileset>
  </delete>
</project>

ls -ltrR alpha
alpha:
total 4
lrwxrwxrwx   1 antoine  antoine        4 Aug 22 10:06 epsilon -> beta
drwxrwxr-x   2 antoine  antoine      512 Aug 22 10:06 beta
-rw-rw-r--   1 antoine  antoine        0 Aug 22 10:06 alpha.xml

alpha/beta:
total 0
-rw-rw-r--   1 antoine  antoine        0 Aug 22 10:06 epsilon.xml
I am closing this again as WORKSFORME. 
Comment 4 Brian Compton 2003-08-22 18:39:38 UTC
Sorry to have to reopen this again, but your solution does not work if what you 
are trying to do is delete a directory. Yes, the directory pointed to by the 
symbolic link was not touched which is great. But, the symbolic link was not 
deleted either. So, if I had wanted to delete the "alpha" directory completely, 
I cannot. 

Here is a script I have been testing with along with the output:

<project name="deltest" default="delete">
  <target name="delete">
    <exec executable='ls' os='UNIX:Linux:SunOS'>
      <arg value="-alR"/>
    </exec>
    <mkdir dir="xx/yy"/>
    <touch file="xx/yy/f1"/>
    <touch file="xx/yy/f2"/>
    <mkdir dir="aa"/>
    <touch file="aa/f3"/>
    <touch file="aa/f4"/>
    <exec executable='ln' os='UNIX:Linux:SunOS'>
      <arg value='-s'/>
      <arg path='aa'/>
      <arg path='xx/yy/zz'/>
    </exec>
    <exec executable='ls' os='UNIX:Linux:SunOS'>
      <arg value="-alR"/>
    </exec>
    <delete verbose="true" includeEmptyDirs="true">
      <fileset dir="xx" followsymlinks="false">
        <include name="yy/**"/>
      </fileset>
    </delete>
    <exec executable='ls' os='UNIX:Linux:SunOS'>
      <arg value="-alR"/>
    </exec>
  </target>
</project>

===================================================================

Buildfile: build.xml

delete:
     [exec] .:
     [exec] total 6
     [exec] drwxr-xr-x   2 dynamo6  dynamo6      512 Aug 22 11:33 .
     [exec] drwxr-xr-x   6 dynamo6  dynamo6      512 Aug 22 11:25 ..
     [exec] -rw-r--r--   1 dynamo6  dynamo6      811 Aug 22 11:34 build.xml
    [mkdir] Created dir: /export/home/dynamo6/tmp/test2/xx/yy
    [touch] Creating /export/home/dynamo6/tmp/test2/xx/yy/f1
    [touch] Creating /export/home/dynamo6/tmp/test2/xx/yy/f2
    [mkdir] Created dir: /export/home/dynamo6/tmp/test2/aa
    [touch] Creating /export/home/dynamo6/tmp/test2/aa/f3
    [touch] Creating /export/home/dynamo6/tmp/test2/aa/f4
     [exec] .:
     [exec] total 10
     [exec] drwxr-xr-x   4 dynamo6  dynamo6      512 Aug 22 11:34 .
     [exec] drwxr-xr-x   6 dynamo6  dynamo6      512 Aug 22 11:25 ..
     [exec] drwxr-xr-x   2 dynamo6  dynamo6      512 Aug 22 11:34 aa
     [exec] -rw-r--r--   1 dynamo6  dynamo6      811 Aug 22 11:34 build.xml
     [exec] drwxr-xr-x   3 dynamo6  dynamo6      512 Aug 22 11:34 xx

     [exec] ./aa:
     [exec] total 4
     [exec] drwxr-xr-x   2 dynamo6  dynamo6      512 Aug 22 11:34 .
     [exec] drwxr-xr-x   4 dynamo6  dynamo6      512 Aug 22 11:34 ..
     [exec] -rw-r--r--   1 dynamo6  dynamo6        0 Aug 22 11:34 f3
     [exec] -rw-r--r--   1 dynamo6  dynamo6        0 Aug 22 11:34 f4

     [exec] ./xx:
     [exec] total 6
     [exec] drwxr-xr-x   3 dynamo6  dynamo6      512 Aug 22 11:34 .
     [exec] drwxr-xr-x   4 dynamo6  dynamo6      512 Aug 22 11:34 ..
     [exec] drwxr-xr-x   2 dynamo6  dynamo6      512 Aug 22 11:34 yy

     [exec] ./xx/yy:
     [exec] total 6
     [exec] drwxr-xr-x   2 dynamo6  dynamo6      512 Aug 22 11:34 .
     [exec] drwxr-xr-x   3 dynamo6  dynamo6      512 Aug 22 11:34 ..
     [exec] -rw-r--r--   1 dynamo6  dynamo6        0 Aug 22 11:34 f1
     [exec] -rw-r--r--   1 dynamo6  dynamo6        0 Aug 22 11:34 f2
     [exec] lrwxrwxrwx   1 dynamo6  dynamo6       33 Aug 22 11:34 zz -
> /export/home/dynamo6/tmp/test2/aa
   [delete] Deleting 2 files from /export/home/dynamo6/tmp/test2/xx
   [delete] Deleting /export/home/dynamo6/tmp/test2/xx/yy/f1
   [delete] Deleting /export/home/dynamo6/tmp/test2/xx/yy/f2
     [exec] .:
     [exec] total 10
     [exec] drwxr-xr-x   4 dynamo6  dynamo6      512 Aug 22 11:34 .
     [exec] drwxr-xr-x   6 dynamo6  dynamo6      512 Aug 22 11:25 ..
     [exec] drwxr-xr-x   2 dynamo6  dynamo6      512 Aug 22 11:34 aa
     [exec] -rw-r--r--   1 dynamo6  dynamo6      811 Aug 22 11:34 build.xml
     [exec] drwxr-xr-x   3 dynamo6  dynamo6      512 Aug 22 11:34 xx

     [exec] ./aa:
     [exec] total 4
     [exec] drwxr-xr-x   2 dynamo6  dynamo6      512 Aug 22 11:34 .
     [exec] drwxr-xr-x   4 dynamo6  dynamo6      512 Aug 22 11:34 ..
     [exec] -rw-r--r--   1 dynamo6  dynamo6        0 Aug 22 11:34 f3
     [exec] -rw-r--r--   1 dynamo6  dynamo6        0 Aug 22 11:34 f4

     [exec] ./xx:
     [exec] total 6
     [exec] drwxr-xr-x   3 dynamo6  dynamo6      512 Aug 22 11:34 .
     [exec] drwxr-xr-x   4 dynamo6  dynamo6      512 Aug 22 11:34 ..
     [exec] drwxr-xr-x   2 dynamo6  dynamo6      512 Aug 22 11:34 yy

     [exec] ./xx/yy:
     [exec] total 6
     [exec] drwxr-xr-x   2 dynamo6  dynamo6      512 Aug 22 11:34 .
     [exec] drwxr-xr-x   3 dynamo6  dynamo6      512 Aug 22 11:34 ..
     [exec] lrwxrwxrwx   1 dynamo6  dynamo6       33 Aug 22 11:34 zz -
> /export/home/dynamo6/tmp/test2/aa

BUILD SUCCESSFUL
Total time: 3 seconds
Comment 5 Stefan Bodewig 2003-08-25 13:35:34 UTC
Just to make sure I get this right.  You want a setting that somehow deletes
the symlink itself without following it, right?

There doesn't seem to be a way to do that right now.  It's debatable whether
it is a bug or a missing feature given the very limited support for symbolic
links (or file operations in general) in the Java runtime.  Please let me
mark this as an enhancement request, even if a valid and important one.
Comment 6 Brian Compton 2003-08-25 13:50:38 UTC
Yes, but I would go a step further. It seems to me that the safest option 
should be the default, so in a unix/linux environment where symlinks are 
supported, <delete dir="xxx"> should act exactly like "rm -rf xxx" which would 
reliably remove the directory including any symlinks, but does not delete 
anything pointed to by the symlink. 

If for some reason, someone DOES NOT want to delete symlinks if the exist or 
they want to follow symlinks and delete files, they should have to choose that 
option. It should not be the default.

Thanks!
Comment 7 Gus Heck 2003-08-25 15:08:17 UTC
Changing past behavior breaks back compatability. It is entirely possible that
there is some segment of the ant user comunity that is relying on the link
following behavior. There is a strong bias against breaking builds that used to
work. 

As for deleting a symlink, yes that is possible IF the user has the ability to
rename the *target* of the link. The trick is to rename the target (causing a
broken link) which will then be deleted. After the link is deleted, the target's
name  is restored. This round about approach is a limitation of the "Java knows
nothing about symlinks" problem. It is unclear why broken links can be deleted,
but that is how it seems to work. 

I have implemented a <symlink action="delete"> wich will be available in 1.6
(and is currently available in nightly builds), so I suspect it would be
feaseable to write a selector that selected symlinks (noone has done this yet,
but it shouldn't be too hard using the
org.apache.tools.ant.util.FileUtils.isSymbolicLink(File parent, String name)
method, and then feed the results of the selector that to symlink delete before
doing your delete of the directory. But if the user running the build doesn't
have enough access to the *target* of the link it will still fail because
<symlink> uses the technique mentioned above. 

Perhaps with the advent of the Tiger 1.5 java release, which is supposed to have
better support for dealing with native filesystems, this can be improved (for
those who run ant using Tiger... The same old reflect or fallback pattern that
we used for all the 1.1 compatability stuff will apply).
Comment 8 Brianna Sollandry 2008-03-22 10:45:24 UTC
I just got bit - hard - by this issue.

I'm running OS X 10.5.2.
I have Ant 1.7.0.

 I had the following in my build.xml:

<mkdir dir="${dist}/temp"/>
<symlink action="single" link="${dist}/temp/Applications" resource="/Applications" />
...
<delete dir="${dist}/temp" />

In other words, I created a temporary directory, stuck in a symbolic link to /Applications, did some stuff, and deleted the temporary directory.

Ant proceeded to delete 7,800 some files out of /Applications. Fortunately, I run Time Machine and was able to recover completely within 20 minutes or so. But, it was pretty unnerving.

Considering that a recursive delete from the shell deletes the symbolic link rather than following it and deleting at the target, it never occurred to me that the ant delete task would behave this way.

Unfortunately, as I just reported in another bug report, <symlink action="delete" ...>" doesn't work for me, so I can't clean up my temp directory.
Comment 9 Stefan Bodewig 2008-09-04 06:31:57 UTC
even though bug 36658 I mark them this way around since the later contains a (not yet evaluated) patch.

*** This bug has been marked as a duplicate of bug 36658 ***