Refactor opendir.
authorRoland McGrath <roland@hack.frob.com>
Mon, 18 May 2015 22:44:53 +0000 (15:44 -0700)
committerRoland McGrath <roland@hack.frob.com>
Mon, 18 May 2015 22:44:53 +0000 (15:44 -0700)
ChangeLog
sysdeps/posix/opendir.c

index b7f3c61..1c4f896 100644 (file)
--- a/ChangeLog
+++ b/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.
index 451c56e..6509f5c 100644 (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
-    {
-      /* 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)
-       return NULL;
-      if (__glibc_unlikely (! S_ISDIR (statbuf.st_mode)))
-       {
-         __set_errno (ENOTDIR);
-         return NULL;
-        }
-    }
+  return true;
+}
+
 
+static int
+opendir_oflags (void)
+{
   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 flags;
+}
+
+
+static DIR *
+opendir_tail (int fd)
+{
+  if (__glibc_unlikely (fd < 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.  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)))
     {
-      /* 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;
+      __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.  */
+      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);
-       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)