changeset 12017:acc38673eec3

canonicalize-lgpl: reject non-directory with trailing slash This synchronizes glibc to gnulib. For gnulib to glibc, see: http://sources.redhat.com/bugzilla/show_bug.cgi?id=10635 * lib/canonicalize-lgpl.c (__realpath): Synchronize with glibc. * tests/test-canonicalize-lgpl.c (main): Enhance test. This catches failures in glibc 2.3.5. * tests/test-canonicalize.c (main): Likewise. Signed-off-by: Eric Blake <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Fri, 11 Sep 2009 13:31:06 -0600
parents 4fac822214af
children 586fda772b8f
files ChangeLog lib/canonicalize-lgpl.c tests/test-canonicalize-lgpl.c tests/test-canonicalize.c
diffstat 4 files changed, 121 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2009-09-17  Eric Blake  <ebb9@byu.net>
 
+	canonicalize-lgpl: reject non-directory with trailing slash
+	* lib/canonicalize-lgpl.c (__realpath): Synchronize with glibc.
+	* tests/test-canonicalize-lgpl.c (main): Enhance test.  This
+	catches failures in glibc 2.3.5.
+	* tests/test-canonicalize.c (main): Likewise.
+
 	canonicalize-lgpl: use native realpath if it works
 	* lib/canonicalize-lgpl.c (realpath): Guard with
 	FUNC_REALPATH_WORKS.
--- a/lib/canonicalize-lgpl.c
+++ b/lib/canonicalize-lgpl.c
@@ -1,5 +1,5 @@
 /* Return the canonical absolute name of a given file.
-   Copyright (C) 1996-2003, 2005-2009 Free Software Foundation, Inc.
+   Copyright (C) 1996-2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    This program is free software: you can redistribute it and/or modify
@@ -15,38 +15,25 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#include <config.h>
+#ifndef _LIBC
+# include <config.h>
+#endif
 
 #if !HAVE_CANONICALIZE_FILE_NAME || defined _LIBC
 
-#include <alloca.h>
-
 /* Specification.  */
 #include <stdlib.h>
 
-#include <stddef.h>
+#include <alloca.h>
 #include <string.h>
 #include <unistd.h>
-
 #include <limits.h>
-
 #if HAVE_SYS_PARAM_H || defined _LIBC
 # include <sys/param.h>
 #endif
-#ifndef MAXSYMLINKS
-# ifdef SYMLOOP_MAX
-#  define MAXSYMLINKS SYMLOOP_MAX
-# else
-#  define MAXSYMLINKS 20
-# endif
-#endif
-
 #include <sys/stat.h>
-
 #include <errno.h>
-#ifndef _LIBC
-# define __set_errno(e) errno = (e)
-#endif
+#include <stddef.h>
 
 #ifdef _LIBC
 # include <shlib-compat.h>
@@ -70,6 +57,14 @@
 #  define __getcwd(buf, max) getwd (buf)
 # endif
 # define __readlink readlink
+# define __set_errno(e) errno = (e)
+# ifndef MAXSYMLINKS
+#  ifdef SYMLOOP_MAX
+#   define MAXSYMLINKS SYMLOOP_MAX
+#  else
+#   define MAXSYMLINKS 20
+#  endif
+# endif
 #endif
 
 #if !FUNC_REALPATH_WORKS || defined _LIBC
@@ -155,6 +150,7 @@
 #else
       struct stat st;
 #endif
+      int n;
 
       /* Skip sequence of multiple path-separators.  */
       while (*start == '/')
@@ -232,7 +228,6 @@
 	    {
 	      char *buf;
 	      size_t len;
-	      int n;
 
 	      if (++num_links > MAXSYMLINKS)
 		{
@@ -287,6 +282,11 @@
 		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] == '/')
@@ -296,16 +296,14 @@
   if (extra_buf)
     freea (extra_buf);
 
-  return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath;
+  return rpath;
 
 error:
   {
     int saved_errno = errno;
     if (extra_buf)
       freea (extra_buf);
-    if (resolved)
-      strcpy (resolved, rpath);
-    else
+    if (resolved == NULL)
       free (rpath);
     errno = saved_errno;
   }
@@ -317,6 +315,7 @@
 
 #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
 char *
+attribute_compat_text_section
 __old_realpath (const char *name, char *resolved)
 {
   if (resolved == NULL)
--- a/tests/test-canonicalize-lgpl.c
+++ b/tests/test-canonicalize-lgpl.c
@@ -82,6 +82,24 @@
     ASSERT (errno == EINVAL);
   }
 
+  /* Check that a non-directory with trailing slash yields NULL.  */
+  {
+    char *result;
+    errno = 0;
+    result = canonicalize_file_name (BASE "/tra/");
+    ASSERT (result == NULL);
+    ASSERT (errno == ENOTDIR);
+  }
+
+  /* Check that a missing directory yields NULL.  */
+  {
+    char *result;
+    errno = 0;
+    result = canonicalize_file_name (BASE "/zzz/..");
+    ASSERT (result == NULL);
+    ASSERT (errno == ENOENT);
+  }
+
   /* From here on out, tests involve symlinks.  */
   if (symlink (BASE "/ket", "ise") != 0)
     {
@@ -137,6 +155,24 @@
     ASSERT (errno == ENOENT);
   }
 
+  /* Check that a non-directory symlink with trailing slash yields NULL.  */
+  {
+    char *result;
+    errno = 0;
+    result = canonicalize_file_name (BASE "/huk/");
+    ASSERT (result == NULL);
+    ASSERT (errno == ENOTDIR);
+  }
+
+  /* Check that a missing directory via symlink yields NULL.  */
+  {
+    char *result;
+    errno = 0;
+    result = canonicalize_file_name (BASE "/ouk/..");
+    ASSERT (result == NULL);
+    ASSERT (errno == ENOENT);
+  }
+
   /* Check that a loop of symbolic links is detected.  */
   {
     char *result;
--- a/tests/test-canonicalize.c
+++ b/tests/test-canonicalize.c
@@ -90,6 +90,34 @@
     ASSERT (errno == EINVAL);
   }
 
+  /* Check that a non-directory with trailing slash yields NULL.  */
+  {
+    char *result1;
+    char *result2;
+    errno = 0;
+    result1 = canonicalize_file_name (BASE "/tra/");
+    ASSERT (result1 == NULL);
+    ASSERT (errno == ENOTDIR);
+    errno = 0;
+    result2 = canonicalize_filename_mode (BASE "/tra/", CAN_EXISTING);
+    ASSERT (result2 == NULL);
+    ASSERT (errno == ENOTDIR);
+  }
+
+  /* Check that a missing directory yields NULL.  */
+  {
+    char *result1;
+    char *result2;
+    errno = 0;
+    result1 = canonicalize_file_name (BASE "/zzz/..");
+    ASSERT (result1 == NULL);
+    ASSERT (errno == ENOENT);
+    errno = 0;
+    result2 = canonicalize_filename_mode (BASE "/zzz/..", CAN_EXISTING);
+    ASSERT (result2 == NULL);
+    ASSERT (errno == ENOENT);
+  }
+
   /* From here on out, tests involve symlinks.  */
   if (symlink (BASE "/ket", "ise") != 0)
     {
@@ -163,6 +191,34 @@
     ASSERT (errno == ENOENT);
   }
 
+  /* Check that a non-directory symlink with trailing slash yields NULL.  */
+  {
+    char *result1;
+    char *result2;
+    errno = 0;
+    result1 = canonicalize_file_name (BASE "/huk/");
+    ASSERT (result1 == NULL);
+    ASSERT (errno == ENOTDIR);
+    errno = 0;
+    result2 = canonicalize_filename_mode (BASE "/huk/", CAN_EXISTING);
+    ASSERT (result2 == NULL);
+    ASSERT (errno == ENOTDIR);
+  }
+
+  /* Check that a missing directory via symlink yields NULL.  */
+  {
+    char *result1;
+    char *result2;
+    errno = 0;
+    result1 = canonicalize_file_name (BASE "/ouk/..");
+    ASSERT (result1 == NULL);
+    ASSERT (errno == ENOENT);
+    errno = 0;
+    result2 = canonicalize_filename_mode (BASE "/ouk/..", CAN_EXISTING);
+    ASSERT (result2 == NULL);
+    ASSERT (errno == ENOENT);
+  }
+
   /* Check that a loop of symbolic links is detected.  */
   {
     char *result1;