canonicalize-lgpl: reject non-directory with trailing slash
authorEric Blake <ebb9@byu.net>
Fri, 11 Sep 2009 19:31:06 +0000 (13:31 -0600)
committerEric Blake <ebb9@byu.net>
Fri, 18 Sep 2009 01:16:28 +0000 (19:16 -0600)
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>
ChangeLog
lib/canonicalize-lgpl.c
tests/test-canonicalize-lgpl.c
tests/test-canonicalize.c

index 681fc48..2e406a6 100644 (file)
--- 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.
index edf91e2..63aecb5 100644 (file)
@@ -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
    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>
 #  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 @@ __realpath (const char *name, char *resolved)
 #else
       struct stat st;
 #endif
+      int n;
 
       /* Skip sequence of multiple path-separators.  */
       while (*start == '/')
@@ -232,7 +228,6 @@ __realpath (const char *name, char *resolved)
            {
              char *buf;
              size_t len;
-             int n;
 
              if (++num_links > MAXSYMLINKS)
                {
@@ -287,6 +282,11 @@ __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] == '/')
@@ -296,16 +296,14 @@ __realpath (const char *name, char *resolved)
   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 @@ versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
 
 #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)
index 704c0ec..f2c4e7a 100644 (file)
@@ -82,6 +82,24 @@ main ()
     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 @@ main ()
     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;
index 6614422..010ca70 100644 (file)
@@ -90,6 +90,34 @@ main ()
     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 @@ main ()
     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;