Subject: bug#10305: coreutils-8.14, "rm -r" fails with EBADF

From: Jim Meyering <[email-masked]>
Date: Fri, 16 Dec 2011 14:14:52 +0100

Joachim Schmitz wrote:
>> From: Jim Meyering [mailto:[email-masked]]
>> Sent: Friday, December 16, 2011 11:51 AM
>> To: Joachim Schmitz
>> Cc: 'Paul Eggert'; [email-masked]; [email-masked]
>> Subject: Re: coreutils-8.14, "rm -r" fails with EBADF
>>
>> Joachim Schmitz wrote:
>>
>> >> From: Paul Eggert [mailto:[email-masked]]
>> >> Sent: Thursday, December 15, 2011 7:07 PM
>> >> To: Joachim Schmitz
>> >> Cc: Jim Meyering; [email-masked]; [email-masked]
>> >> Subject: Re: coreutils-8.14, "rm -r" fails with EBADF
>> >>
>> >> On 12/15/11 08:28, Jim Meyering wrote:
> ...
>> > So... it seems we can't dup() an fd for a directory here!
>>
>> Right.
>> Your config.h file suggests you're not using a gnulib dup replacement, so
> I
>> suspect a bug in your system's dup implementation.
>
> Hmm, I can dup() an fd for a directory if or had been open()'d O_RDONLY, but
> not if opened O_WRONLY or O_RDWR, I'll get an EISDIR from open() then.

The FDs in fts.c should all be opened with O_RDONLY (among other flags),
but not O_WRONLY or O_RDWR.  Maybe one of these other flags is what's
making your dup fail:

static inline int
internal_function
diropen (FTS const *sp, char const *dir)
{
  int open_flags = (O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
                    | (ISSET (FTS_PHYSICAL) ? O_NOFOLLOW : 0)
                    | (ISSET (FTS_NOATIME) ? O_NOATIME : 0));

static inline DIR *
internal_function
opendirat (int fd, char const *dir, int extra_flags, int *pdir_fd)
{
  int new_fd = openat (fd, dir,
                       (O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
                        | extra_flags));

>> I thought gnulib had pretty good dup* test coverage, but see that no dup*
> test
>> uses a directory file descriptor.
>
> Any workaround?

For your problem, try removing those other O_* flags.

For the test suite with inadequate coverage: add dirfd-using tests.