Refactor opendir.

This commit is contained in:
Roland McGrath 2015-05-18 15:44:53 -07:00
parent eefe64b9a1
commit 46f894d8c6
2 changed files with 100 additions and 44 deletions

View File

@ -1,3 +1,19 @@
2015-05-18 Roland McGrath <roland@hack.frob.com>
* sysdeps/posix/opendir.c: Include <stdbool.h>.
(invalid_name): New function, broken out of ...
(__opendirat): ... here. Call it.
(need_isdir_precheck): New function, broken out of ...
(__opendirat): ... here. Call it.
Use __fxstatat64, not __xstatat64.
(opendir_oflags): New function, broken out of ...
(__opendirat): ... here. Call it.
(opendir_tail): New function, broken out of ...
(__opendirat): ... here. Call it.
(__opendir): Call invalid_name, need_isdir_precheck, __xstat64, and
opendir_tail, rather than punting to __opendirat.
(__opendirat): Conditionalize function definition on [IS_IN (libc)].
2015-05-18 Siddhesh Poyarekar <siddhesh@redhat.com>
* .gitignore: Ignore generated *.pyc.

View File

@ -18,6 +18,7 @@
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <dirent.h>
@ -81,83 +82,122 @@ tryopen_o_directory (void)
#endif
DIR *
internal_function
__opendirat (int dfd, const char *name)
static bool
invalid_name (const char *name)
{
struct stat64 statbuf;
struct stat64 *statp = NULL;
if (__builtin_expect (name[0], '\1') == '\0')
if (__glibc_unlikely (name[0] == '\0'))
{
/* POSIX.1-1990 says an empty name gets ENOENT;
but `open' might like it fine. */
__set_errno (ENOENT);
return NULL;
return true;
}
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. */
if (o_directory_works < 0)
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)
{
if (__glibc_unlikely (fd < 0))
return NULL;
/* Now make sure this really is a directory and nothing changed since the
`stat' call. The S_ISDIR check is superfluous if O_DIRECTORY works,
but it's cheap and we need the stat call for st_blksize anyway. */
struct stat64 statbuf;
if (__glibc_unlikely (__fxstat64 (_STAT_VER, fd, &statbuf) < 0))
goto lose;
if (__glibc_unlikely (! S_ISDIR (statbuf.st_mode)))
{
__set_errno (ENOTDIR);
lose:
close_not_cancel_no_status (fd);
return NULL;
}
return __alloc_dir (fd, true, 0, &statbuf);
}
#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. */
if (__builtin_expect (__xstat64 (_STAT_VER, name, &statbuf), 0) < 0)
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;
}
}
int flags = O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
#endif
int fd;
#if IS_IN (rtld)
assert (dfd == AT_FDCWD);
fd = open_not_cancel_2 (name, flags);
#else
fd = openat_not_cancel_3 (dfd, name, flags);
#endif
if (__builtin_expect (fd, 0) < 0)
return NULL;
#ifdef O_DIRECTORY
if (o_directory_works <= 0)
#endif
{
/* Now make sure this really is a directory and nothing changed since
the `stat' call. */
if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0)
goto lose;
if (__glibc_unlikely (! S_ISDIR (statbuf.st_mode)))
{
__set_errno (ENOTDIR);
lose:
close_not_cancel_no_status (fd);
return NULL;
}
statp = &statbuf;
}
return __alloc_dir (fd, true, 0, statp);
return opendir_tail (openat_not_cancel_3 (dfd, name, opendir_oflags ()));
}
#endif
/* Open a directory stream on NAME. */
DIR *
__opendir (const char *name)
{
return __opendirat (AT_FDCWD, 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 ()));
}
weak_alias (__opendir, opendir)