Speed up realpath and fix EOVERFLOW bug
Commit Message
[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(-)
@@ -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] == '/')