This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] realpath: allow // to be handled specially
- From: Eric Blake <eblake at redhat dot com>
- To: libc-alpha at sourceware dot org
- Cc: Eric Blake <ebb9 at byu dot net>
- Date: Tue, 1 Oct 2013 13:28:17 -0600
- Subject: [PATCH] realpath: allow // to be handled specially
- Authentication-results: sourceware.org; auth=none
From: Eric Blake <ebb9@byu.net>
Fixes BZ #10635.
POSIX states that //path may be distinct from /path; while
GNU/Linux does not make this distinction, the code for
canonicalize is copied via gnulib to other platforms (such
as cygwin) where this makes a difference in the behavior of
realpath.
Also, free() is allowed to clobber the original errno value.
* stdlib/canonicalize.c (__realpath): Add and honor
DOUBLE_SLASH_IS_DISTINCT_ROOT. Also, avoid clobbering errno
during free.
---
I have copyright assignment, but am still working on getting
push rights; depending on whether review or push rights takes
longer, someone may need to push on my behalf.
ChangeLog | 7 +++++++
stdlib/canonicalize.c | 56 +++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 52 insertions(+), 11 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 55bcf08..1866e09 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2013-10-01 Eric Blake <eblake@redhat.com>
+
+ realpath: allow // to be handled specially
+ * stdlib/canonicalize.c (__realpath): Add and honor
+ DOUBLE_SLASH_IS_DISTINCT_ROOT. Also, avoid clobbering errno
+ during free.
+
2013-09-30 Petr Machata <pmachata@redhat.com>
* elf/elf.h (R_AARCH64_ABS16): New macro.
diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c
index 784c978..ca2a1b5 100644
--- a/stdlib/canonicalize.c
+++ b/stdlib/canonicalize.c
@@ -28,6 +28,11 @@
#include <eloop-threshold.h>
#include <shlib-compat.h>
+/* Define this to 1 if you want realpath to honor leading //. */
+#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
+# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
+#endif
+
/* Return the canonical absolute name of file NAME. A canonical name
does not contain any `.', `..' components nor any repeated path
separators ('/') or symlinks. All path components must exist. If
@@ -46,6 +51,7 @@ __realpath (const char *name, char *resolved)
const char *start, *end, *rpath_limit;
long int path_max;
int num_links = 0;
+ int saved_errno;
if (name == NULL)
{
@@ -88,6 +94,7 @@ __realpath (const char *name, char *resolved)
if (!__getcwd (rpath, path_max))
{
rpath[0] = '\0';
+ saved_errno = errno;
goto error;
}
dest = __rawmemchr (rpath, '\0');
@@ -96,6 +103,8 @@ __realpath (const char *name, char *resolved)
{
rpath[0] = '/';
dest = rpath + 1;
+ if (DOUBLE_SLASH_IS_DISTINCT_ROOT && name[1] == '/')
+ *dest++ = '/';
}
for (start = end = name; *start; start = end)
@@ -120,6 +129,9 @@ __realpath (const char *name, char *resolved)
/* Back up to previous component, ignore if at root already. */
if (dest > rpath + 1)
while ((--dest)[-1] != '/');
+ if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
+ && *dest == '/')
+ dest++;
}
else
{
@@ -135,7 +147,7 @@ __realpath (const char *name, char *resolved)
if (resolved)
{
- __set_errno (ENAMETOOLONG);
+ saved_errno = ENAMETOOLONG;
if (dest > rpath + 1)
dest--;
*dest = '\0';
@@ -148,7 +160,10 @@ __realpath (const char *name, char *resolved)
new_size += path_max;
new_rpath = (char *) realloc (rpath, new_size);
if (new_rpath == NULL)
- goto error;
+ {
+ saved_errno = ENOMEM;
+ goto error;
+ }
rpath = new_rpath;
rpath_limit = rpath + new_size;
@@ -159,7 +174,10 @@ __realpath (const char *name, char *resolved)
*dest = '\0';
if (__lxstat64 (_STAT_VER, rpath, &st) < 0)
- goto error;
+ {
+ saved_errno = errno;
+ goto error;
+ }
if (S_ISLNK (st.st_mode))
{
@@ -168,13 +186,16 @@ __realpath (const char *name, char *resolved)
if (++num_links > __eloop_threshold ())
{
- __set_errno (ELOOP);
+ saved_errno = ELOOP;
goto error;
}
n = __readlink (rpath, buf, path_max - 1);
if (n < 0)
- goto error;
+ {
+ saved_errno = errno;
+ goto error;
+ }
buf[n] = '\0';
if (!extra_buf)
@@ -183,7 +204,7 @@ __realpath (const char *name, char *resolved)
len = strlen (end);
if ((long int) (n + len) >= path_max)
{
- __set_errno (ENAMETOOLONG);
+ saved_errno = ENAMETOOLONG;
goto error;
}
@@ -192,21 +213,33 @@ __realpath (const char *name, char *resolved)
name = end = memcpy (extra_buf, buf, n);
if (buf[0] == '/')
- dest = rpath + 1; /* It's an absolute symlink */
+ {
+ dest = rpath + 1; /* It's an absolute symlink */
+ if (DOUBLE_SLASH_IS_DISTINCT_ROOT && buf[1] == '/')
+ *dest++ = '/';
+ }
else
- /* Back up to previous component, ignore if at root already: */
- if (dest > rpath + 1)
- while ((--dest)[-1] != '/');
+ {
+ /* Back up to previous component, ignore if at root
+ already: */
+ if (dest > rpath + 1)
+ while ((--dest)[-1] != '/');
+ if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
+ && *dest == '/')
+ dest++;
+ }
}
else if (!S_ISDIR (st.st_mode) && *end != '\0')
{
- __set_errno (ENOTDIR);
+ saved_errno = ENOTDIR;
goto error;
}
}
}
if (dest > rpath + 1 && dest[-1] == '/')
--dest;
+ if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && *dest == '/')
+ dest++;
*dest = '\0';
assert (resolved == NULL || resolved == rpath);
@@ -216,6 +249,7 @@ error:
assert (resolved == NULL || resolved == rpath);
if (resolved == NULL)
free (rpath);
+ __set_errno (saved_errno);
return NULL;
}
versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
--
1.8.3.1