This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] realpath: allow // to be handled specially


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]