Subject: bug#9813: rm -rf calls rmdir() prior to close(), which can fail

From: Eric Blake <[email-masked]>
Date: Thu, 20 Oct 2011 13:57:20 -0600

On 10/20/2011 01:47 PM, Paul Eggert wrote:
> On 10/20/11 10:38, Eric Blake wrote:
>> POSIX is clear that attempts to rmdir() a directory that still has open descriptors may fail.
>
> Hmm, that's news to me.  And on the contrary, the spec
> <http://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html>
> explicitly talks about what rmdir() does when there are open descriptors:
>
>   "If one or more processes have the directory open when the last link is removed,
>    the dot and dot-dot entries, if present, shall be removed before rmdir() returns
>    and no new entries may be created in the directory, but the directory shall not
>    be removed until all references to the directory are closed."
>
> which very much sounds like rmdir() is supposed to succeed in this case.
>
> Also, there's no entry for this situation under the "may fail" section
> of ERRORS.  And there's longstanding Unix tradition that you can unlink
> a file that you have an open file descriptor to, which suggests that
> rmdir() should do likewise.

That's because it's a shall fail, not a may fail error:

[EBUSY]
The directory to be removed is currently in use by the system or some 
process and the implementation considers this to be an error.

>
> So, if this is a problem under Cygwin, it's probably better to handle it
> in the rmdir() wrapper that deals with Cygwin and file descriptors.

It's more than just cygwin.  And while cygwin _is_ working around this 
in many cases (cygwin is going to some rather extreme lengths for NTFS 
and NFS, for example), it only works on a per-filesystem basis (the 
latest bug is that a Novell device driver, exposing the NWFS file 
system, has bugs in its mapping to Windows system calls that are 
preventing cygwin's normal workarounds from working).  But even when 
cygwin can work around it, it is expensive (it involves reopening the 
handle multiple times, with varying level of permission requests, to see 
if the file is previously opened in sharing mode, and depending on that 
result, temporarily moving the file to the recycle bin so that it will 
disappear when the last handle closes); whereas fixing coreutils to do 
things in the correct order in the first place would make the overall rm 
process faster because it isn't wasting time on corner case file 
shuffling for a directory that is being deleted in the first place.

At any rate, this is a regression introduced by coreutils 8.0, when rm 
switched to fts().  Prior to that point, coreutils used the correct 
ordering, where rmdir() was not attempted until after the close(); and 
the Cygwin report demonstrated that coreutils 7.0 worked on NWFS where 
coreutils 8.x fails.

-- 
Eric Blake   [email-masked]    +1-801-349-2682
Libvirt virtualization library http://libvirt.org