Re: `rmdir .` doesn't work in 2.4

Alexander Viro
2001-01-09T13:40:24Z

On Mon, 8 Jan 2001, Stefan Traby wrote:

> On Mon, Jan 08, 2001 at 12:58:20PM -0500, Alexander Viro wrote:
>
> > Shell equivalent is rmdir `pwd`. Also portable.
>
> Very portable - not.
>
> rmdir "`pwd`" !!!

OK, got me on that. Yes, you'll need quoting here. Sorry.
Notice that there are two effects in the game:
* some Unices refuse to rmdir() busy directories. For them
removing the pwd is impossible. Period. You can chdir() away, but
there is no promise that after
chdir foo
chdir ..
foo will refer to the directory that used to be your pwd in the middle.
That's pretty obvious - consider the effect of

chdir foo
chdir .. mv foo bar
mv baz foo
So unless you have external information about behaviour of other processes
the only way to pinpoint a directory is to keep it opened/pwd/root. Each
of these will keep it busy and Unices that refuse to rmdir() busy ones
will return -EBUSY on that.
On such systems there is _no_ reliable way to remove your current
pwd unless you can guarantee that it won't be renamed away by another process.
No matter what you are doing.

* All Unices are required to refuse rmdir() on pathnames that end on
"." or "..". 2.2 is an exception in that respect - usually it allows such
operation. However, that is _still_ unreliable. rename() called by another
process in the right time will make rmdir(".") return -ENOENT, even though
at any moment "." would resolve to the same directory. Including the window
when rmdir() would fail. Notice that error value is indistinguishable from
the other cases, so blind repeating rmdir(".") while you get -ENOENT is not
a solution (as the matter of fact, it can trivially turn into infinite loop).
All examples mentioned in that thread (HP/UX, Solaris, *BSD) _will_
fail with "rmdir .". Some of them will fail with "rmdir <your_pwd>" too -
see discussion of -EBUSY above.

The bottom line: without external information about behaviour of
other processes you can't reliably remove the directory that is your pwd
now. "chdir away and rmdir by the name it used to have" works around the
problem with -EBUSY (on the systems that refuse to remove busy ones) _BUT_
it is still vulnerable to "rename by another process" kind of races.

If you _have_ such external warranties - trivial wrapper will do
the trick on the systems that allow rmdir() of busy directories and
the same wrapper combined with chdir away will solve the problem for all
systems. There is no reason to put that in the kernel - it will not give
you any additional warranties.

We _can_ pinpoint the link and do rmdir() on it reliably. We can't
do the same to inode. In principle kernel could do that, but NONE of the
existing Unices (2.2 included) do such things and it would require more
trickery than it's worth.