changeset 12058:36183b482b71

readlink: fix cygwin 1.5.x bug with return type On older systems, readlink returned int instead of ssize_t, making the use of readlink via function pointer harder. * m4/readlink.m4 (gl_FUNC_READLINK): Require correct signature. * lib/unistd.in.h (readlink): Use ssize_t. * lib/readlink.c (readlink): Likewise. * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Add witness. * modules/unistd (Makefile.am): Substitute it. * lib/unistd.in.h (readlink): Declare replacement. * doc/posix-functions/readlink.texi (readlink): Document this. Signed-off-by: Eric Blake <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Tue, 22 Sep 2009 17:14:23 -0600
parents aee865e7b49f
children 6babf16a67dd
files ChangeLog doc/posix-functions/readlink.texi lib/readlink.c lib/unistd.in.h m4/readlink.m4 m4/unistd_h.m4 modules/unistd
diffstat 7 files changed, 58 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2009-09-23  Eric Blake  <ebb9@byu.net>
 
+	readlink: fix cygwin 1.5.x bug with return type
+	* m4/readlink.m4 (gl_FUNC_READLINK): Require correct signature.
+	* lib/unistd.in.h (readlink): Use ssize_t.
+	* lib/readlink.c (readlink): Likewise.
+	* m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Add witness.
+	* modules/unistd (Makefile.am): Substitute it.
+	* lib/unistd.in.h (readlink): Declare replacement.
+	* doc/posix-functions/readlink.texi (readlink): Document this.
+
 	symlink: use throughout gnulib
 	* m4/symlinkat.m4 (gl_FUNC_SYMLINKAT): Omit symlink check.
 	* lib/symlinkat.c (symlinkat) [!HAVE_SYMLINK]: Document why
--- a/doc/posix-functions/readlink.texi
+++ b/doc/posix-functions/readlink.texi
@@ -9,6 +9,10 @@
 Portability problems fixed by Gnulib:
 @itemize
 @item
+On some platforms, @code{readlink} returns @code{int} instead of
+@code{ssize_t}:
+FreeBSD 6.0, OpenBSD 3.8, Cygwin 1.5.x.
+@item
 This function is missing on some platforms:
 mingw.
 @end itemize
--- a/lib/readlink.c
+++ b/lib/readlink.c
@@ -1,5 +1,5 @@
 /* Stub for readlink().
-   Copyright (C) 2003-2007 Free Software Foundation, Inc.
+   Copyright (C) 2003-2007, 2009 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -20,30 +20,39 @@
 #include <unistd.h>
 
 #include <errno.h>
-#include <sys/types.h>
+#include <string.h>
 #include <sys/stat.h>
-#include <stddef.h>
 
 #if !HAVE_READLINK
 
 /* readlink() substitute for systems that don't have a readlink() function,
    such as DJGPP 2.03 and mingw32.  */
 
-/* The official POSIX return type of readlink() is ssize_t, but since here
-   we have no declaration in a public header file, we use 'int' as return
-   type.  */
-
-int
-readlink (const char *path, char *buf, size_t bufsize)
+ssize_t
+readlink (const char *name, char *buf _UNUSED_PARAMETER_,
+          size_t bufsize _UNUSED_PARAMETER_)
 {
   struct stat statbuf;
 
   /* In general we should use lstat() here, not stat().  But on platforms
-     without symbolic links lstat() - if it exists - would be equivalent to
+     without symbolic links, lstat() - if it exists - would be equivalent to
      stat(), therefore we can use stat().  This saves us a configure check.  */
-  if (stat (path, &statbuf) >= 0)
+  if (stat (name, &statbuf) >= 0)
     errno = EINVAL;
   return -1;
 }
 
-#endif
+#else /* HAVE_READLINK */
+
+# undef readlink
+
+/* readlink() wrapper that uses correct types, for systems like cygwin
+   1.5.x where readlink returns int.  */
+
+ssize_t
+rpl_readlink (const char *name, char *buf, size_t bufsize)
+{
+  return readlink (name, buf, bufsize);
+}
+
+#endif /* HAVE_READLINK */
--- a/lib/unistd.in.h
+++ b/lib/unistd.in.h
@@ -41,7 +41,9 @@
 /* mingw, BeOS, Haiku declare environ in <stdlib.h>, not in <unistd.h>.  */
 #include <stdlib.h>
 
-#if @GNULIB_WRITE@ && @REPLACE_WRITE@ && @GNULIB_UNISTD_H_SIGPIPE@
+#if ((@GNULIB_WRITE@ && @REPLACE_WRITE@ && @GNULIB_UNISTD_H_SIGPIPE@)   \
+     || (@GNULIB_READLINK@ && (!@HAVE_READLINK@ || @REPLACE_READLINK@)) \
+     || (@GNULIB_READLINKAT@ && !@HAVE_READLINKAT@))
 /* Get ssize_t.  */
 # include <sys/types.h>
 #endif
@@ -621,13 +623,16 @@
 
 
 #if @GNULIB_READLINK@
+# if @REPLACE_READLINK@
+#  define readlink rpl_readlink
+# endif
 /* Read the contents of the symbolic link FILE and place the first BUFSIZE
    bytes of it into BUF.  Return the number of bytes placed into BUF if
    successful, otherwise -1 and errno set.
    See the POSIX:2001 specification
    <http://www.opengroup.org/susv3xsh/readlink.html>.  */
-# if !@HAVE_READLINK@
-extern int readlink (const char *file, char *buf, size_t bufsize);
+# if !@HAVE_READLINK@ || @REPLACE_READLINK@
+extern ssize_t readlink (const char *file, char *buf, size_t bufsize);
 # endif
 #elif defined GNULIB_POSIXCHECK
 # undef readlink
--- a/m4/readlink.m4
+++ b/m4/readlink.m4
@@ -1,4 +1,4 @@
-# readlink.m4 serial 5
+# readlink.m4 serial 6
 dnl Copyright (C) 2003, 2007, 2009 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -12,6 +12,19 @@
     HAVE_READLINK=0
     AC_LIBOBJ([readlink])
     gl_PREREQ_READLINK
+  else
+    AC_CACHE_CHECK([whether readlink signature is correct],
+      [gl_cv_decl_readlink_works],
+      [AC_COMPILE_IFELSE(
+         [AC_LANG_PROGRAM(
+           [[#include <unistd.h>
+      /* Cause compilation failure if original declaration has wrong type.  */
+      ssize_t readlink (const char *, char *, size_t);]])],
+         [gl_cv_decl_readlink_works=yes], [gl_cv_decl_readlink_works=no])])
+    if test "$gl_cv_decl_readlink_works" != yes; then
+      REPLACE_READLINK=1
+      AC_LIBOBJ([readlink])
+    fi
   fi
 ])
 
--- a/m4/unistd_h.m4
+++ b/m4/unistd_h.m4
@@ -101,6 +101,7 @@
   REPLACE_LCHOWN=0;       AC_SUBST([REPLACE_LCHOWN])
   REPLACE_LINK=0;         AC_SUBST([REPLACE_LINK])
   REPLACE_LSEEK=0;        AC_SUBST([REPLACE_LSEEK])
+  REPLACE_READLINK=0;     AC_SUBST([REPLACE_READLINK])
   REPLACE_RMDIR=0;        AC_SUBST([REPLACE_RMDIR])
   REPLACE_SYMLINK=0;      AC_SUBST([REPLACE_SYMLINK])
   REPLACE_UNLINK=0;       AC_SUBST([REPLACE_UNLINK])
--- a/modules/unistd
+++ b/modules/unistd
@@ -93,6 +93,7 @@
 	      -e 's|@''REPLACE_LCHOWN''@|$(REPLACE_LCHOWN)|g' \
 	      -e 's|@''REPLACE_LINK''@|$(REPLACE_LINK)|g' \
 	      -e 's|@''REPLACE_LSEEK''@|$(REPLACE_LSEEK)|g' \
+	      -e 's|@''REPLACE_READLINK''@|$(REPLACE_READLINK)|g' \
 	      -e 's|@''REPLACE_RMDIR''@|$(REPLACE_RMDIR)|g' \
 	      -e 's|@''REPLACE_SYMLINK''@|$(REPLACE_SYMLINK)|g' \
 	      -e 's|@''REPLACE_UNLINK''@|$(REPLACE_UNLINK)|g' \