mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-08 22:30:07 +00:00
Refactor opendir.
This commit is contained in:
parent
eefe64b9a1
commit
46f894d8c6
16
ChangeLog
16
ChangeLog
@ -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.
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user