@@ -55,6 +55,7 @@ __realpath (const char *name, char *resolved)
const char *start, *end, *rpath_limit;
const size_t path_max = PATH_MAX;
int num_links = 0;
+ char buf[PATH_MAX];
char extra_buf[PATH_MAX];
if (name == NULL)
@@ -104,12 +105,6 @@ __realpath (const char *name, char *resolved)
for (end = start; *start; start = end)
{
-#ifdef _LIBC
- struct stat64 st;
-#else
- struct stat st;
-#endif
-
/* Skip sequence of multiple path-separators. */
while (*start == '/')
++start;
@@ -118,12 +113,25 @@ __realpath (const char *name, char *resolved)
for (end = start; *end && *end != '/'; ++end)
/* Nothing. */;
- if (end - start == 0)
- break;
- else if (end - start == 1 && start[0] == '.')
+ if (end - start == 1 && start[0] == '.')
/* nothing */;
else if (end - start == 2 && start[0] == '.' && start[1] == '.')
{
+ ssize_t n;
+
+ if (dest[-1] != '/')
+ *dest++ = '/';
+ *dest = '\0';
+
+ n = __readlink (rpath, buf, path_max - 1);
+ if (n == -1)
+ {
+ if (errno == ENOTDIR && dest[-1] == '/')
+ dest[-1] = '\0';
+ if (errno != EINVAL)
+ goto error;
+ }
+
/* Back up to previous component, ignore if at root already. */
if (dest > rpath + 1)
for (--dest; dest > rpath && dest[-1] != '/'; --dest)
@@ -132,6 +140,7 @@ __realpath (const char *name, char *resolved)
else
{
size_t new_size;
+ ssize_t n;
if (dest[-1] != '/')
*dest++ = '/';
@@ -166,25 +175,23 @@ __realpath (const char *name, char *resolved)
dest = __mempcpy (dest, start, end - start);
*dest = '\0';
- if (__lstat64 (rpath, &st) < 0)
- goto error;
-
- if (S_ISLNK (st.st_mode))
+ n = __readlink (rpath, buf, path_max - 1);
+ if (n < 0)
+ {
+ if (errno == ENOTDIR && dest[-1] == '/')
+ dest[-1] = '\0';
+ if (errno != EINVAL)
+ goto error;
+ }
+ else
{
- char buf[PATH_MAX];
size_t len;
- ssize_t n;
if (++num_links > __eloop_threshold ())
{
__set_errno (ELOOP);
goto error; }
- n = __readlink (rpath, buf, path_max - 1);
- if (n < 0)
- goto error;
- buf[n] = '\0';
-
len = strlen (end);
/* Check that n + len + 1 doesn't overflow and is <= path_max. */
if (n >= SIZE_MAX - len || n + len >= path_max)
@@ -211,11 +218,6 @@ __realpath (const char *name, char *resolved)
continue;
}
}
- else if (!S_ISDIR (st.st_mode) && *end != '\0')
- {
- __set_errno (ENOTDIR);
- goto error;
- }
}
}
if (dest > rpath + 1 && dest[-1] == '/')