Subject: Re: bug#19051: rm symboliclink/ # "Is a directory"

From: Pádraig Brady <[email-masked]>
Date: Fri, 14 Nov 2014 14:47:37 +0000

On 14/11/14 13:15, Eric Blake wrote:
> On 11/14/2014 04:41 AM, Pádraig Brady wrote:
>> tag 19051 notabug
>> close 19501
>> stop
>>
>> On 14/11/14 06:53, aaron brick wrote:
>>> hi folks,
>>>
>>> $ ln -s / sl
>>> $ rm sl/
>>> rm: cannot remove `sl/': Is a directory
>>> $ rm sl
>>> $
>>>
> 
>>
>> Confused me too when I encountered it first, but tt's required by POSIX:
>> http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11
> 
> No, actually, POSIX requires that it (attempt to) remove the DIRECTORY,
> not the symlink.  Linux is intentionally in violation of POSIX on this
> front.

Right, that's what I meant. In the original `rm` context above
the directory is (implicitly) referenced.
On all platforms `rm sl/` it will fail.

Following on to the rmdir() issue..
I changed your example below to rmdir which I presume you meant?
Yes solaris leaves the dangling symlink in this case.

> Try this on Solaris:
> $ mkdir a
> $ ln -s a b
> $ rmdir b/
> $ ls -d ?
> b

>> But now I see that coreutils rmdir is inconsistent and doesn't
>> treat sl/ as the directory. We should probably fix that up
>> to be consistent with other tools, POSIX and other systems.
> 
> We've had this conversation in the past.  The fact that Linux
> intentionally violates POSIX is actually useful; the POSIX behavior
> leaves behind dangling symlinks, whereas the Linux behavior makes some
> sort of sense (even if not the best quality errno values).  Our decision
> has been that we choose NOT to override kernel semantics on this front;
> waiting for either the kernel folks to obey POSIX (unlikely) or for
> POSIX to relax and concede that the Linux behavior is a useful
> alternative and allow it in addition to Solaris behavior (possible, but
> I haven't tried pushing hard for it lately).

Thanks for the insight.

So usually a trailing / is treated as the directory itself:

$ mkdir a
$ ln -s a b

$ ls -Fd b/
b//
$ ls -Fd b
b@

$ stat b -c %F
symbolic link
$ stat b/ -c %F
directory

Also in this case coreutils generates that good error internally
without attempting to unlink anything.

$ rm b/
rm: cannot remove ‘b/’: Is a directory

Then we get to the inconsistent Linux behaviour:

$ strace -e unlinkat rm -R b/
unlinkat(AT_FDCWD, "b/", AT_REMOVEDIR)  = -1 ENOTDIR (Not a directory)
rm: cannot remove ‘b/’: Not a directory

$ strace -e rmdir rmdir b/
rmdir("b/")                             = -1 ENOTDIR (Not a directory)
rmdir: failed to remove ‘b/’: Not a directory

I disagree with the inconsistent kernel behavior here,
though agree we shouldn't try to work around it.

thanks,
Pádraig.