From 413bb8ca872b5a7e8a241a9c55334afe400dad06 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Tue, 20 Oct 1998 23:03:20 +0000 Subject: [PATCH] Update. 1998-10-18 Zack Weinberg * sysdeps/unix/opendir.c: Check at runtime for kernel support for O_DIRECTORY. --- ChangeLog | 5 ++++ sysdeps/unix/opendir.c | 65 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4543eb2..fbe6bc4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +1998-10-18 Zack Weinberg + + * sysdeps/unix/opendir.c: Check at runtime for kernel support for + O_DIRECTORY. + 1998-10-20 H.J. Lu * sysdeps/unix/sysv/linux/i386/setresuid.c (__setresuid): Fix diff --git a/sysdeps/unix/opendir.c b/sysdeps/unix/opendir.c index 067dc2c..3cbd662 100644 --- a/sysdeps/unix/opendir.c +++ b/sysdeps/unix/opendir.c @@ -29,9 +29,40 @@ #include - -#ifndef O_DIRECTORY -# define O_DIRECTORY 0 +/* opendir() must not accidentally open something other than a directory. + Some OS's have kernel support for that, some don't. In the worst + case we have to stat() before the open() AND fstat() after. + + We have to test at runtime for kernel support since libc may have + been compiled with different headers to the kernel it's running on. + This test can't be done reliably in the general case. We'll use + /dev/null, which if it's not a device lots of stuff will break, as + a guinea pig. It may be missing in chroot environments, so we + make sure to fail safe. */ +#ifdef O_DIRECTORY +static int o_directory_works = -1; + +static void +tryopen_o_directory (void) +{ + int serrno = errno; + int x = __open ("/dev/null", O_RDONLY|O_NDELAY|O_DIRECTORY); + + if (x >= 0) + { + __close (x); + o_directory_works = 0; + } + else if (errno != ENOTDIR) + o_directory_works = 0; + else + o_directory_works = 1; + + __set_errno (serrno); +} +# define EXTRA_FLAGS O_DIRECTORY +#else +# define EXTRA_FLAGS 0 #endif @@ -53,18 +84,28 @@ __opendir (const char *name) return NULL; } - /* We first have to check whether the name is for a directory. We - cannot do this after the open() call since the open/close operation - performed on, say, a tape device might have undesirable effects. */ - if (__stat (name, &statbuf) < 0) - return NULL; - if (! S_ISDIR (statbuf.st_mode)) +#ifdef O_DIRECTORY + /* Test whether O_DIRECTORY works. */ + if (o_directory_works == -1) + tryopen_o_directory (); + + /* We can skip the expensive `stat' call if O_DIRECTORY works. */ + if (o_directory_works == 0) +#endif { - __set_errno (ENOTDIR); - return NULL; + /* We first have to check whether the name is for a directory. We + cannot do this after the open() call since the open/close operation + performed on, say, a tape device might have undesirable effects. */ + if (__stat (name, &statbuf) < 0) + return NULL; + if (! S_ISDIR (statbuf.st_mode)) + { + __set_errno (ENOTDIR); + return NULL; + } } - fd = __open (name, O_RDONLY|O_NDELAY|O_DIRECTORY); + fd = __open (name, O_RDONLY|O_NDELAY|EXTRA_FLAGS); if (fd < 0) return NULL; -- 2.7.4