summaryrefslogtreecommitdiff
path: root/sysdeps/posix/opendir.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/posix/opendir.c')
-rw-r--r--sysdeps/posix/opendir.c159
1 files changed, 15 insertions, 144 deletions
diff --git a/sysdeps/posix/opendir.c b/sysdeps/posix/opendir.c
index 3e09deb805..bb6bd7cc85 100644
--- a/sysdeps/posix/opendir.c
+++ b/sysdeps/posix/opendir.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991-2016 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -15,24 +15,13 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
+#include <errno.h>
+#include <stdio.h> /* For BUFSIZ. */
+#include <sys/param.h> /* For MIN and MAX. */
-#include <dirstream.h>
#include <not-cancel.h>
-#include <kernel-features.h>
/* The st_blksize value of the directory is used as a hint for the
size of the buffer which receives struct dirent values from the
@@ -40,47 +29,9 @@
file system provides a bogus value. */
#define MAX_DIR_BUFFER_SIZE 1048576U
-/* 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
-# ifdef O_DIRECTORY_WORKS
-# define o_directory_works 1
-# define tryopen_o_directory() while (1) /* This must not be called. */
-# else
-static int o_directory_works;
-
-static void
-tryopen_o_directory (void)
-{
- int serrno = errno;
- int x = open_not_cancel_2 ("/dev/null", O_RDONLY|O_NDELAY|O_DIRECTORY);
-
- if (x >= 0)
- {
- close_not_cancel_no_status (x);
- o_directory_works = -1;
- }
- else if (errno != ENOTDIR)
- o_directory_works = -1;
- else
- o_directory_works = 1;
-
- __set_errno (serrno);
-}
-# endif
-# define EXTRA_FLAGS O_DIRECTORY
-#else
-# define EXTRA_FLAGS 0
-#endif
-
+enum {
+ opendir_oflags = O_RDONLY|O_NDELAY|O_DIRECTORY|O_LARGEFILE|O_CLOEXEC
+};
static bool
invalid_name (const char *name)
@@ -95,33 +46,6 @@ invalid_name (const char *name)
return false;
}
-
-static bool
-need_isdir_precheck (void)
-{
-#ifdef O_DIRECTORY
- /* Test whether O_DIRECTORY works. */
- if (o_directory_works == 0)
- tryopen_o_directory ();
-
- /* We can skip the expensive `stat' call if O_DIRECTORY works. */
- return o_directory_works < 0;
-#endif
- return true;
-}
-
-
-static int
-opendir_oflags (void)
-{
- int flags = O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE;
-#ifdef O_CLOEXEC
- flags |= O_CLOEXEC;
-#endif
- return flags;
-}
-
-
static DIR *
opendir_tail (int fd)
{
@@ -138,7 +62,7 @@ opendir_tail (int fd)
{
__set_errno (ENOTDIR);
lose:
- close_not_cancel_no_status (fd);
+ __close_nocancel_nostatus (fd);
return NULL;
}
@@ -148,29 +72,12 @@ opendir_tail (int fd)
#if IS_IN (libc)
DIR *
-internal_function
__opendirat (int dfd, const char *name)
{
if (__glibc_unlikely (invalid_name (name)))
return NULL;
- if (need_isdir_precheck ())
- {
- /* 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. */
- struct stat64 statbuf;
- if (__glibc_unlikely (__fxstatat64 (_STAT_VER, dfd, name,
- &statbuf, 0) < 0))
- return NULL;
- if (__glibc_unlikely (! S_ISDIR (statbuf.st_mode)))
- {
- __set_errno (ENOTDIR);
- return NULL;
- }
- }
-
- return opendir_tail (openat_not_cancel_3 (dfd, name, opendir_oflags ()));
+ return opendir_tail (__openat_nocancel (dfd, name, opendir_oflags));
}
#endif
@@ -182,54 +89,18 @@ __opendir (const char *name)
if (__glibc_unlikely (invalid_name (name)))
return NULL;
- if (need_isdir_precheck ())
- {
- /* 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. */
- struct stat64 statbuf;
- if (__glibc_unlikely (__xstat64 (_STAT_VER, name, &statbuf) < 0))
- return NULL;
- if (__glibc_unlikely (! S_ISDIR (statbuf.st_mode)))
- {
- __set_errno (ENOTDIR);
- return NULL;
- }
- }
-
- return opendir_tail (open_not_cancel_2 (name, opendir_oflags ()));
+ return opendir_tail (__open_nocancel (name, opendir_oflags));
}
weak_alias (__opendir, opendir)
-
-#ifdef __ASSUME_O_CLOEXEC
-# define check_have_o_cloexec(fd) 1
-#else
-static int
-check_have_o_cloexec (int fd)
-{
- if (__have_o_cloexec == 0)
- __have_o_cloexec = (__fcntl (fd, F_GETFD, 0) & FD_CLOEXEC) == 0 ? -1 : 1;
- return __have_o_cloexec > 0;
-}
-#endif
-
-
DIR *
-internal_function
__alloc_dir (int fd, bool close_fd, int flags, const struct stat64 *statp)
{
- /* We always have to set the close-on-exit flag if the user provided
- the file descriptor. Otherwise only if we have no working
- O_CLOEXEC support. */
-#ifdef O_CLOEXEC
- if ((! close_fd && (flags & O_CLOEXEC) == 0)
- || ! check_have_o_cloexec (fd))
-#endif
- {
- if (__builtin_expect (__fcntl (fd, F_SETFD, FD_CLOEXEC), 0) < 0)
+ /* We have to set the close-on-exit flag if the user provided the
+ file descriptor. */
+ if (!close_fd
+ && __glibc_unlikely (__fcntl64_nocancel (fd, F_SETFD, FD_CLOEXEC) < 0))
goto lose;
- }
const size_t default_allocation = (4 * BUFSIZ < sizeof (struct dirent64)
? sizeof (struct dirent64) : 4 * BUFSIZ);
@@ -256,7 +127,7 @@ __alloc_dir (int fd, bool close_fd, int flags, const struct stat64 *statp)
if (close_fd)
{
int save_errno = errno;
- close_not_cancel_no_status (fd);
+ __close_nocancel_nostatus (fd);
__set_errno (save_errno);
}
return NULL;