changeset 17998:227d30aa4e05

readlinkat: avoid OS X 10.10 trailing slash bug * doc/posix-functions/readlink.texi: Mention that OS X 10.10 has this bug. * doc/posix-functions/readlinkat.texi: Likewise. Also mention that OS X 10.10 has this function. * lib/readlinkat.c (rpl_readlinkat): Handle the trailing slash bug, as done for readlink(). * m4/readlinkat.m4 (gl_FUNC_READLINKAT): Check for the readlink() trailing slash bug, and assume readlinkat() has the same issue. Also fix a typo where $gl_cv_decl_readlink_works was tested, rather than the correct $gl_cv_decl_readlinkat_works.
author Pádraig Brady <P@draigBrady.com>
date Sun, 31 May 2015 03:08:52 +0100
parents f7535e681d93
children 1d1da0edcfb2
files ChangeLog doc/posix-functions/readlink.texi doc/posix-functions/readlinkat.texi lib/readlinkat.c m4/readlinkat.m4
diffstat 5 files changed, 51 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2015-05-31  Pádraig Brady  <P@draigBrady.com>
+
+	readlinkat: avoid OS X 10.10 trailing slash bug
+	* doc/posix-functions/readlink.texi: Mention that OS X 10.10
+	has this bug.
+	* doc/posix-functions/readlinkat.texi: Likewise.  Also mention
+	that OS X 10.10 has this function.
+	* lib/readlinkat.c (rpl_readlinkat): Handle the trailing slash bug,
+	as done for readlink().
+	* m4/readlinkat.m4 (gl_FUNC_READLINKAT): Check for the readlink()
+	trailing slash bug, and assume readlinkat() has the same issue.
+	Also fix a typo where $gl_cv_decl_readlink_works was tested,
+	rather than the correct $gl_cv_decl_readlinkat_works.
+
 2015-05-29  Andreas Gruenbacher  <andreas.gruenbacher@gmail.com>
 
 	acl-permissions: Fix build on Mac OS X and older AIX (Bug#20681)
--- a/doc/posix-functions/readlink.texi
+++ b/doc/posix-functions/readlink.texi
@@ -10,7 +10,7 @@
 @itemize
 @item
 Some platforms mistakenly succeed on @code{readlink("link/",buf,len)}:
-FreeBSD 7.2, Solaris 9.
+FreeBSD 7.2, Solaris 9, Mac OS X 10.10.
 @item
 On some platforms, @code{readlink} returns @code{int} instead of
 @code{ssize_t}:
--- a/doc/posix-functions/readlinkat.texi
+++ b/doc/posix-functions/readlinkat.texi
@@ -10,10 +10,13 @@
 @itemize
 @item
 This function is missing on some platforms:
-glibc 2.3.6, Mac OS X 10.5, FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8,
+glibc 2.3.6, Mac OS X < 10.10, FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8,
 AIX 5.1, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 1.5.x, mingw, MSVC 9, Interix 3.5, BeOS.
 But the replacement function is not safe to be used in libraries and is not multithread-safe.
 @item
+Some platforms mistakenly succeed on @code{readlink("link/",buf,len)}:
+Mac OS X 10.10.
+@item
 On some platforms, @code{readlinkat} returns @code{int} instead of
 @code{ssize_t}:
 AIX 7.1.
--- a/lib/readlinkat.c
+++ b/lib/readlinkat.c
@@ -18,7 +18,10 @@
 
 #include <config.h>
 
+#include <errno.h>
 #include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
 
 #if HAVE_READLINKAT
 
@@ -27,6 +30,21 @@
 ssize_t
 rpl_readlinkat (int fd, char const *file, char *buf, size_t len)
 {
+# if READLINK_TRAILING_SLASH_BUG
+  size_t file_len = strlen (file);
+  if (file_len && file[file_len - 1] == '/')
+    {
+      /* Even if FILE without the slash is a symlink to a directory,
+         both lstat() and stat() must resolve the trailing slash to
+         the directory rather than the symlink.  We can therefore
+         safely use stat() to distinguish between EINVAL and
+         ENOTDIR/ENOENT, avoiding extra overhead of rpl_lstat().  */
+      struct stat st;
+      if (stat (file, &st) == 0)
+        errno = EINVAL;
+      return -1;
+    }
+# endif /* READLINK_TRAILING_SLASH_BUG */
   return readlinkat (fd, file, buf, len);
 }
 
--- a/m4/readlinkat.m4
+++ b/m4/readlinkat.m4
@@ -1,4 +1,4 @@
-# serial 4
+# serial 5
 # See if we need to provide readlinkat replacement.
 
 dnl Copyright (C) 2009-2015 Free Software Foundation, Inc.
@@ -13,6 +13,7 @@
   AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
   AC_CHECK_FUNCS_ONCE([readlinkat])
+  AC_REQUIRE([gl_FUNC_READLINK])
   if test $ac_cv_func_readlinkat = no; then
     HAVE_READLINKAT=0
   else
@@ -25,8 +26,17 @@
              ssize_t readlinkat (int, char const *, char *, size_t);]])],
          [gl_cv_decl_readlinkat_works=yes],
          [gl_cv_decl_readlinkat_works=no])])
-    if test "$gl_cv_decl_readlink_works" != yes; then
-      REPLACE_READLINKAT=1
-    fi
+    # Assume readinkat has the same trailing slash bug as readlink,
+    # as is the case on Mac Os X 10.10
+    case "$gl_cv_func_readlink_works" in
+      *yes)
+        if test "$gl_cv_decl_readlinkat_works" != yes; then
+          REPLACE_READLINKAT=1
+        fi
+        ;;
+      *)
+        REPLACE_READLINKAT=1
+        ;;
+    esac
   fi
 ])