fdopendir: fix a bug on systems lacking openat and /proc support
authorJim Meyering <meyering@redhat.com>
Fri, 8 Oct 2010 16:42:59 +0000 (18:42 +0200)
committerJim Meyering <meyering@redhat.com>
Fri, 8 Oct 2010 20:04:06 +0000 (22:04 +0200)
commita1885e2dc2a8f1c79ead4e6ceca1a53827b89048
tree00f1e42aa371b36c4c17842a5ce628ad201e7dcd
parentfe621e2e212dbedcbc80f5b7991717b18d5d8443
fdopendir: fix a bug on systems lacking openat and /proc support

OpenBSD 4.7 is one such system.  The most noticeable effect was
failure of any application making nontrivial use of fts: rm, du,
chown, chmod etc.  E.g., "mkdir -p a/b; ./rm -rf a" would fail with
  ./rm: traversal failed: `a': Bad file descriptor
Debugging that, you see that even though FD 6 was closed just
prior to the opendir call in fd_clone_opendir, its resulting
dir->dd_fd was 8, rather than the expected value of 6:

Breakpoint 3, fdopendir_with_dup (fd=6, older_dupfd=-1) at fdopendir.c:93
93                close (fd);
(gdb) n
94                dir = fd_clone_opendir (dupfd);
(gdb) n
95                saved_errno = errno;
(gdb) p dir->dd_fd
$11 = 8

Notice how it closes FD 6, then gets a DIR* pointer using FD 8.
The problem is that on OpenBSD, fd_clone_opendir has to resort
to using the old-style save/restore CWD mechanism, due to its
lack of openat/proc support, and *that* would steal the FD (6)
that opendir was supposed to use.

The fix is to squirrel away the desired FD so that save_cwd uses a
different one, and then free the dest FD right before calling opendir.
That guarantees opendir will use the required file descriptor.

* lib/fdopendir.c (fd_clone_opendir): Handle the above.
ChangeLog
lib/fdopendir.c