]> Savannah Git Hosting - gnulib.git/commitdiff
glob: simplify symlink detection
authorPaul Eggert <eggert@cs.ucla.edu>
Thu, 31 Aug 2017 21:34:24 +0000 (14:34 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Thu, 31 Aug 2017 22:08:44 +0000 (15:08 -0700)
* 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.

ChangeLog
lib/glob.c

index 58f42dbf637d237ee7f4c3c5d68ebcb62041e76f..f372dbd388a5eef5dce9fa8e9f98193e20cecb4b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
index a1e50d7090a2c0bbb75278d38a6bb3342cae5731..6113af6fd69cc87f571fd60adb5c1733a0d23244 100644 (file)
 \f
 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;
-}
-
-/* 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 */
+  return d.type;
+#else
 # define D_TYPE_TO_RESULT(source)
-
-/* If we do not have type information, symbolic links and directories
-   are always a possibility.  */
-
-static bool
-readdir_result_might_be_symlink (struct readdir_result d)
-{
-  return true;
+  return DT_UNKNOWN;
+#endif
 }
 
+/* Initialize and return skip_entry member of struct readdir_result.  */
 static bool
-readdir_result_might_be_dir (struct readdir_result d)
+readdir_result_skip_entry (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 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
               }
               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))
                     {