diff mbox

Speed up realpath and fix EOVERFLOW bug

Message ID 20200219210339.173576-1-eggert@cs.ucla.edu
State New
Headers show

Commit Message

Paul Eggert Feb. 19, 2020, 9:03 p.m. UTC
[BZ#24970]
* stdlib/canonicalize.c: Do not include <sys/stat.h>; no longer needed.
(__realpath): Use __readlink instead of __lxstat64 to determine
whether RPATH is a symbolic link.  This avoids an unnecessary
__lxstat64 when RPATH is a symbolic link and replaces __lxstat64
with __readlink when RPATH is not a symbolic link.  It also avoids
an unnecessary failure if __lxstat64 would fail with errno ==
EOVERFLOW due to timestamp or other integer overflow.  Remove
unnecessary S_ISDIR check, as the next time through the loop will
fail with errno == ENOTDIR as appropriate.
---
 stdlib/canonicalize.c | 28 +++++++++++-----------------
 1 file changed, 11 insertions(+), 17 deletions(-)
diff mbox

Patch

diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c
index cbd885a3c5..cd2051d35f 100644
--- a/stdlib/canonicalize.c
+++ b/stdlib/canonicalize.c
@@ -21,7 +21,6 @@ 
 #include <string.h>
 #include <unistd.h>
 #include <limits.h>
-#include <sys/stat.h>
 #include <errno.h>
 #include <stddef.h>
 
@@ -98,9 +97,10 @@  __realpath (const char *name, char *resolved)
       dest = rpath + 1;
     }
 
+  char *buf = __alloca (path_max);
+
   for (start = end = name; *start; start = end)
     {
-      struct stat64 st;
       int n;
 
       /* Skip sequence of multiple path-separators.  */
@@ -158,12 +158,14 @@  __realpath (const char *name, char *resolved)
 	  dest = __mempcpy (dest, start, end - start);
 	  *dest = '\0';
 
-	  if (__lxstat64 (_STAT_VER, rpath, &st) < 0)
-	    goto error;
-
-	  if (S_ISLNK (st.st_mode))
+	  n = __readlink (rpath, buf, path_max);
+	  if (n < 0)
+	    {
+	      if (errno != EINVAL)
+		goto error;
+	    }
+	  else
 	    {
-	      char *buf = __alloca (path_max);
 	      size_t len;
 
 	      if (++num_links > __eloop_threshold ())
@@ -172,11 +174,6 @@  __realpath (const char *name, char *resolved)
 		  goto error;
 		}
 
-	      n = __readlink (rpath, buf, path_max - 1);
-	      if (n < 0)
-		goto error;
-	      buf[n] = '\0';
-
 	      if (!extra_buf)
 		extra_buf = __alloca (path_max);
 
@@ -187,6 +184,8 @@  __realpath (const char *name, char *resolved)
 		  goto error;
 		}
 
+	      buf[n] = '\0';
+
 	      /* Careful here, end may be a pointer into extra_buf... */
 	      memmove (&extra_buf[n], end, len + 1);
 	      name = end = memcpy (extra_buf, buf, n);
@@ -198,11 +197,6 @@  __realpath (const char *name, char *resolved)
 		if (dest > rpath + 1)
 		  while ((--dest)[-1] != '/');
 	    }
-	  else if (!S_ISDIR (st.st_mode) && *end != '\0')
-	    {
-	      __set_errno (ENOTDIR);
-	      goto error;
-	    }
 	}
     }
   if (dest > rpath + 1 && dest[-1] == '/')