rmdir(".") works, and causes havoc

Janos Farkas (Janos.Farkas-#UXgkwad/7VpCrajhoVIVTfXkkmy@shadow.banki.hu)
Mon, 4 Aug 1997 14:10:35 +0200


Hi!

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.. :)

[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.

[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.

[iceq] /usr/src/havoc 517> touch losing

Oops, that might be bad...

[iceq] /usr/src/havoc 518> touch thistoo
[iceq] /usr/src/havoc 519> df -i .
Filesystem Inodes IUsed IFree %IUsed Mounted on
/dev/hda7 201960 35945 166015 18% /usr
[iceq] /usr/src/havoc 520> cd ..
[iceq] /usr/src 521> df -i .
Filesystem Inodes IUsed IFree %IUsed Mounted on
/dev/hda7 201960 35945 166015 18% /usr
[iceq] /usr/src 522> ls -ali havoc
ls: havoc: No such file or directory

That's certainly bad... a forced e2fsck will find all of them on the
next run, but until that, all of the inodes are lost. Note also that
leaving the killed directory with chdir() won't free the killed
directory now, even if no files have been created in it.

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. First, I think the kernel
either should not allow to create inodes in a killed directory, it
worked like this before, (or maybe free them all if the directory is
really killed, but that's not a real option), or... the next option is
possibly the best for compatibility, albeit a bit hacky. Look what
GNU tar does if the archive includes "./" (might be useful for the
timestamp data), for example, when it is created with

tar zcvf ../anywhere.tar.gz .

write(1, "./\n", 3./
) = 3
mkdir(".", 0755) = -1 EEXIST (File exists)
lstat(".", {st_mode=S_IFDIR|S_ISGID|0755, st_size=1024, ...}) = 0
rmdir(".") = 0
mkdir(".", 0755) = -1 EEXIST (File exists)
lstat(".", {st_mode=S_IFDIR|S_ISGID|0755, st_size=1024, ...}) = 0
rmdir(".") = -1 ENOENT (No such file or directory)

So, GNU tar removes ".", and then goes on to create the files in it, all
of which will be "lost" at the end. The errors reported are a bit strange
too. (rmdir -> ok, mkdir -> EEXIST, rmdir -> ENOENT, huh?).

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), 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.

-- 
Janos - Don't worry, my address works.  I'm just bored of spam.