Hi
I have a system that precaches directory content at opendir call and I found
that coreutils-6.7 rm -r command doesn't work on it (it used to work fine in
coreutils 5).
The problem is this: when walking up to the root in directory tree, rm opens
parent directory with opendir, then deletes its subdirectory with rmdir and
then starts reading the parent with readdir --- readdir reads just deleted
entry, rm tries to delete it again and fails.
opendir caching is allowed by standard
http://www.opengroup.org/onlinepubs/007908799/xsh/readdir.html ("If a file is
removed from or added to the directory after the most recent call to
opendir() or rewinddir(), whether a subsequent call to readdir() returns an
entry for that file is unspecified."), so the system behaves correctly and rm
has a bug.
Here is a trace when I tried rm -rf /A and there was four directories
/A/B/C/D --- it correctly deletes D, but reads entry for 'D' again and fails.
I made a fix --- it modifies AD_pop_and_chdir so that it only returns fd of a
directory but doesn't try to do fdopendir and do fdopendir in remove_dir
after the subdirectory is deleted - it seems to work but it makes the file
even more messy.
Mikulas
The trace of rm -rf /A, I added printfs to opendir, readdir and closedir to
see what happens:
opendir '/A' -> BFFEF950
readdir BFFEF950, pos 0: name '.', dt 4
readdir BFFEF950, pos 1: name '..', dt 4
readdir BFFEF950, pos 2: name 'B', dt 4
opendir '/A/B' -> BFFEF9F0
closedir: BFFEF950
readdir BFFEF9F0, pos 0: name '.', dt 4
readdir BFFEF9F0, pos 1: name '..', dt 4
readdir BFFEF9F0, pos 2: name 'C', dt 4
opendir '/A/B/C' -> BFFEF980
closedir: BFFEF9F0
readdir BFFEF980, pos 0: name '.', dt 4
readdir BFFEF980, pos 1: name '..', dt 4
readdir BFFEF980, pos 2: name 'D', dt 4
opendir '/A/B/C/D' -> BFFEF9C0
closedir: BFFEF980
readdir BFFEF9C0, pos 0: name '.', dt 4
readdir BFFEF9C0, pos 1: name '..', dt 4
closedir: BFFEF9C0
--- note here: it opens the parent directory and then deletes the
subdirectory --- the subsequent readdir will read just deleted
entry
opendir '/A/B/C' -> BFFEBE00
removed directory: `A/B/C/D'
readdir BFFEBE00, pos 0: name '.', dt 4
readdir BFFEBE00, pos 1: name '..', dt 4
--- here: entry 'D' no longer exists, but it is read from cached
information on opendir
readdir BFFEBE00, pos 2: name 'D', dt 4
closedir: BFFEBE00
opendir '/A/B' -> BFFEBE00
readdir BFFEBE00, pos 0: name '.', dt 4
readdir BFFEBE00, pos 1: name '..', dt 4
readdir BFFEBE00, pos 2: name 'C', dt 4
closedir: BFFEBE00
opendir '/A' -> BFFEBE00
readdir BFFEBE00, pos 0: name '.', dt 4
readdir BFFEBE00, pos 1: name '..', dt 4
readdir BFFEBE00, pos 2: name 'B', dt 4
closedir: BFFEBE00