changeset 38782:b119238632f2

glob: simplify symlink detection * lib/glob.c (dirent_type): New type. Use uint_fast8_t not uint8_t, as C99 does not require uint8_t. (DT_UNKNOWN, DT_DIR, DT_LNK) [!HAVE_STRUCT_DIRENT_D_TYPE]: New macros. (struct readdir_result): Use dirent_type. Do not define skip_entry unless it is needed; this saves a byte on platforms lacking d_ino. (readdir_result_type, readdir_result_skip_entry): New functions, replacing ... (readdir_result_might_be_symlink, readdir_result_might_be_dir): ... these functions, which were removed. This makes the callers easier to read. All callers changed. (D_INO_TO_RESULT): Now empty if there is no d_ino.
author Paul Eggert <eggert@cs.ucla.edu>
date Thu, 31 Aug 2017 14:34:24 -0700
parents 23b092891b25
children 939112530b4c
files ChangeLog lib/glob.c
diffstat 2 files changed, 54 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Aug 30 22:32:23 2017 -0700
+++ b/ChangeLog	Thu Aug 31 14:34:24 2017 -0700
@@ -1,3 +1,17 @@
+2017-08-31  Paul Eggert  <eggert@cs.ucla.edu>
+
+	glob: simplify symlink detection
+	* lib/glob.c (dirent_type): New type.  Use uint_fast8_t not
+	uint8_t, as C99 does not require uint8_t.
+	(struct readdir_result): Use it.  Do not define skip_entry unless
+	it is needed; this saves a byte on platforms lacking d_ino.
+	(readdir_result_type, readdir_result_skip_entry):
+	New functions, replacing ...
+	(readdir_result_might_be_symlink, readdir_result_might_be_dir):
+	... these functions, which were removed.  This makes the callers
+	easier to read.  All callers changed.
+	(D_INO_TO_RESULT): Now empty if there is no d_ino.
+
 2017-08-30  Pádraig Brady  <P@draigBrady.com>
 
 	fts-tests: tag as a longrunning-test so not included by default
--- a/lib/glob.c	Wed Aug 30 22:32:23 2017 -0700
+++ b/lib/glob.c	Thu Aug 31 14:34:24 2017 -0700
@@ -92,61 +92,59 @@
 
 static const char *next_brace_sub (const char *begin, int flags) __THROWNL;
 
+typedef uint_fast8_t dirent_type;
+
+#ifndef HAVE_STRUCT_DIRENT_D_TYPE
+/* Any distinct values will do here.
+   Undef any existing macros out of the way.  */
+# undef DT_UNKNOWN
+# undef DT_DIR
+# undef DT_LNK
+# define DT_UNKNOWN 0
+# define DT_DIR 1
+# define DT_LNK 2
+#endif
+
 /* A representation of a directory entry which does not depend on the
    layout of struct dirent, or the size of ino_t.  */
 struct readdir_result
 {
   const char *name;
 #if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
-  uint8_t type;
+  dirent_type type;
 #endif
+#if defined _LIBC || defined D_INO_IN_DIRENT
   bool skip_entry;
+#endif
 };
 
+/* Initialize and return type member of struct readdir_result.  */
+static dirent_type
+readdir_result_type (struct readdir_result d)
+{
 #if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
-/* Initializer based on the d_type member of struct dirent.  */
 # define D_TYPE_TO_RESULT(source) (source)->d_type,
-
-/* True if the directory entry D might be a symbolic link.  */
-static bool
-readdir_result_might_be_symlink (struct readdir_result d)
-{
-  return d.type == DT_UNKNOWN || d.type == DT_LNK;
+  return d.type;
+#else
+# define D_TYPE_TO_RESULT(source)
+  return DT_UNKNOWN;
+#endif
 }
 
-/* True if the directory entry D might be a directory.  */
-static bool
-readdir_result_might_be_dir (struct readdir_result d)
-{
-  return d.type == DT_DIR || readdir_result_might_be_symlink (d);
-}
-#else /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
-# define D_TYPE_TO_RESULT(source)
-
-/* If we do not have type information, symbolic links and directories
-   are always a possibility.  */
-
+/* Initialize and return skip_entry member of struct readdir_result.  */
 static bool
-readdir_result_might_be_symlink (struct readdir_result d)
+readdir_result_skip_entry (struct readdir_result d)
 {
-  return true;
-}
-
-static bool
-readdir_result_might_be_dir (struct readdir_result d)
-{
-  return true;
-}
-
-#endif /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
-
 /* Initializer for skip_entry.  POSIX does not require that the d_ino
    field be present, and some systems do not provide it. */
 #if defined _LIBC || defined D_INO_IN_DIRENT
 # define D_INO_TO_RESULT(source) (source)->d_ino == 0,
+  return d.skip_entry;
 #else
-# define D_INO_TO_RESULT(source) false,
+# define D_INO_TO_RESULT(source)
+  return false;
 #endif
+}
 
 /* Construct an initializer for a struct readdir_result object from a
    struct dirent *.  No copy of the name is made.  */
@@ -1545,19 +1543,24 @@
               }
               if (d.name == NULL)
                 break;
-              if (d.skip_entry)
+              if (readdir_result_skip_entry (d))
                 continue;
 
               /* If we shall match only directories use the information
                  provided by the dirent call if possible.  */
-              if ((flags & GLOB_ONLYDIR) && !readdir_result_might_be_dir (d))
-                continue;
+              if (flags & GLOB_ONLYDIR)
+                switch (readdir_result_type (d))
+                  {
+                  case DT_DIR: case DT_LNK: case DT_UNKNOWN: break;
+                  default: continue;
+                  }
 
               if (fnmatch (pattern, d.name, fnm_flags) == 0)
                 {
                   /* If the file we found is a symlink we have to
                      make sure the target file exists.  */
-                  if (!readdir_result_might_be_symlink (d)
+                  dirent_type type = readdir_result_type (d);
+                  if (! (type == DT_LNK || type == DT_UNKNOWN)
                       || link_exists_p (dfd, directory, dirlen, d.name,
                                         pglob, flags))
                     {