Something's weird about System.Directory.removeDirectoryRecursive

http://hackage.haskell.org/packages/archive/directory/1.1.0.1/doc/html/Syste... The documentation says that removeDirectoryRecursive follows symlinks. However, the implementation doesn't (in most cases, see below). ------------------------------------------------------------------------------------------------------------ $ mkdir test-removeDirectoryRecursive $ cd test-removeDirectoryRecursive $ mkdir a b $ touch a/a.txt b/b.txt $ ln -s $PWD/b a/ $ ln -s $PWD/b/b.txt a/ $ ls -l a total 8.2k -rw-rw-r-- 1 john john 0 2012-01-27 23:33 a.txt lrwxrwxrwx 1 john john 65 2012-01-27 23:33 b -> /home/john/test-removeDirectoryRecursive/b lrwxrwxrwx 1 john john 71 2012-01-27 23:34 b.txt -> /home/john/test-removeDirectoryRecursive/b/b.txt # OK, a/ has a normal file and two symlinks in it. Let's recursively remove a/ and see what happens. $ ghci Prelude> import System.Directory Prelude System.Directory> removeDirectoryRecursive "a" Prelude System.Directory> Leaving GHCi. $ ls -l a b ls: cannot access a: No such file or directory b: total 0 -rw-rw-r-- 1 john john 0 2012-01-27 23:33 b.txt # a/ was removed -- good! # # b/ and its contents are untouched, good, but goes against the docs ------------------------------------------------------------------------------------------------------------ Now, there is one case where this function *will* follow symlinks. However, I believe it is a bug because it produces odd behavior: ------------------------------------------------------------------------------------------------------------ $ sudo mkdir a [sudo] password for john: $ sudo ln -s $PWD/b a/ $ ls -l a b a: total 4.1k lrwxrwxrwx 1 root root 65 2012-01-27 23:38 b -> /home/john/test-removeDirectoryRecursive/b b: total 0 -rw-rw-r-- 1 john john 0 2012-01-27 23:33 b.txt # Now a/ has a symlink, which cannot be deleted, because its containing directory is read-only to the current user. $ rm a/b rm: remove symbolic link `a/b'? y rm: cannot remove `a/b': Permission denied # What happens if removeDirectoryRecursive is called now? $ ghci Prelude> import System.Directory Prelude System.Directory> removeDirectoryRecursive "a" *** Exception: a/b: removeDirectory: permission denied (Permission denied) Prelude System.Directory> Leaving GHCi. $ ls -l a b a: total 4.1k lrwxrwxrwx 1 root root 65 2012-01-27 23:38 b -> /home/john/test-removeDirectoryRecursive/b b: total 0 # a/ is untouched, but b/ has been emptied! ------------------------------------------------------------------------------------------------------------ So what is the expected behavior of this function? What should it do in the presence of symlinks? IMO, the function should be documented as *not* following symlinks, and the directory check should be changed so that it returns False for symlink-to-directory.

On Fri, Jan 27, 2012 at 11:48:33PM -0800, John Millikin wrote:
Now, there is one case where this function *will* follow symlinks. However, I believe it is a bug because it produces odd behavior:
I think this is an oddity in how symlinks to directories are treated. You can remove one with removeFile but not removeDirectory, but doesFileExist returns False and doesDirectoryExist returns True. Thanks Ian

On Thu, Feb 9, 2012 at 17:02, Ian Lynagh
On Fri, Jan 27, 2012 at 11:48:33PM -0800, John Millikin wrote:
Now, there is one case where this function *will* follow symlinks. However, I believe it is a bug because it produces odd behavior:
I think this is an oddity in how symlinks to directories are treated.
You can remove one with removeFile but not removeDirectory, but doesFileExist returns False and doesDirectoryExist returns True.
You probably don't want to use doesDirectoryExist directly here; C programs in this situation use lstat() instead of stat() to check for symlinks, but in the general case you want doesDirectoryExist to use stat() as it currently does. -- brandon s allbery allbery.b@gmail.com wandering unix systems administrator (available) (412) 475-9364 vm/sms
participants (3)
-
Brandon Allbery
-
Ian Lynagh
-
John Millikin