Re: rmdir(".") works, and causes havoc

Linus Torvalds (torvalds@transmeta.com)
Mon, 4 Aug 1997 09:23:24 -0700 (PDT)


On Mon, 4 Aug 1997, Janos Farkas wrote:
>
> There are probably still a few fishy features about dircache, here's
> one more. However, I guess it's a religious issue, at least partly,
> so I won't go ahead fixing it.. :)

No, it's not really a religious issue at all, it's just that the new
dcache code is so different from what any other unix does. And I haven't
checked all the small details (some of the ones you mention I knew about,
others were a nasty surprise that I hadn't thought about).

> [iceq] /usr/src 511> df -i .
> Filesystem Inodes IUsed IFree %IUsed Mounted on
> /dev/hda7 201960 35942 166018 18% /usr
> [iceq] /usr/src 512> mkdir havoc
> [iceq] /usr/src 513> cd havoc/
> [iceq] /usr/src/havoc 514> rmdir .
>
> Possibly ok, but strange.

No. This is one I hadn't thought about, and it's nasty. I think POSIX
explicitly disallows "." for rmdir.

The problem with this one is that it's a special case for normal UNIX path
traversal, but for the new dcache it actually makes perfect sense.

Traditional UNIX path traversal simply cannot do 'rmdir(".")' at all,
because traditionally you'd have no idea how to find the parent and remove
the correct directory.

For the new dcache, 'rmdir(".")' is trivially easy to do, and involves no
special cases at all. I personally think that is a very cool thing, but at
the same time I'm afraid we have to add the silly limits imposed to us by
standards.

NOTE! The reason 'rmdir(".")' is forbidden is not because it's our current
working directory: it's perfectly ok to remove a working directory, and
we've been able to do it before too. The issue is something else: we
didn't actually give a pathname to the last part.

So in the above, "rmdir ../havoc" would actually have been ok, even though
"." and "../havoc" are the same directory. And THAT is what makes the
above such an ugly special case: as far as the dcache is concerned, the
two names really are exactly the same.

> [iceq] /usr/src/havoc 515> df -i .
> Filesystem Inodes IUsed IFree %IUsed Mounted on
> /dev/hda7 201960 35943 166017 18% /usr
> [iceq] /usr/src/havoc 516> ls -ali
> total 2
> 65379 drwxr-sr-x 0 chexum src 1024 Aug 3 21:53 .
> 169473 drwxrwsr-x 15 root src 1024 Aug 3 21:54 ..
>
> This could be ok too, although I guess it's quite different than
> before dircache.

I think the above is actually exactly what an older kernel would have
given us if you'd have done "rmdir ../havoc".

> [iceq] /usr/src/havoc 517> touch losing
>
> Oops, that might be bad...

The above is indeed incorrect, and is again disallowed by POSIX. This was
a nasty I knew about, and this one should actually be pretty easy to fix.

> I remember a discussion many months ago that (maybe) some Sunny OS-es
> prevent the user from removing the cwd, and some thought it's a cool
> feature, and Linus taught them to think first, as that OS simply checks
> the current task's cwd, and that's just for killing performance.
>
> However, this is something different.

Indeed. This isn't about the "cwd" at all, it's really about the name,
nothing else. There are a few strange naming rules that are traditionally
required, and the new dcache makes those rules obsolete from a technical
standpoint (the "." issue for rmdir).

However, even though the reasons are technically obsolete, I'll have to
fix this.

> To prevent all of these, possibly the kernel should refuse to create
> inodes in killed directories (and of course refuse to remove nonempty
> ones, but that's done),

Yes, this is just a bug in the current code - there is actually a test for
it, but the test no longer works because things got changed so much that
the test means something else these days.

> AND refuse to remove "." to prevent GNU tar
> failing to extract every such archive. This last item looks
> suspicious, but IMHO is quite different from preventing to remove the
> cwd of any active process.

As mentioned, the "." issue _is_ different from the cwd. In fact, just to
show an example of this, try:

mkdir havoc
rmdir havoc/.

which has nothing to do with the cwd, but should also fail (but again, the
current linux dcache is entirely happy with the above, because again there
are actually no technical reasons why it should fail - there is only the
traditional UNIX behaviour).

I'll probably just have to add a test for "." and ".." by hand to rmdir().
Sad, because it _could_ be potentially useful, it's just not allowed in
POSIX.

Linus