* doc/posix-functions/symlinkat.texi (symlinkat): Mention AIX porting problem. * lib/symlinkat.c: Always include errno.h. (rpl_symlinkat) [HAVE_SYMLINKAT]: New function. * lib/unistd.in.h (symlinkat): Add replacement machinery. * m4/symlinkat.m4 (gl_FUNC_SYMLINKAT): Check symlinkat behavior. * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Add REPLACE_SYMLINKAT. * modules/symlinkat (Depends-on): Add fstatat if REPLACE_SYMLINKAT. (configure.ac): Also compile replacement if REPLACE_SYMLINKAT. * modules/unistd (unistd.h): Substitute REPLACE_SYMLINKAT. --- ChangeLog | 12 ++++++++++++ doc/posix-functions/symlinkat.texi | 4 ++++ lib/symlinkat.c | 23 ++++++++++++++++++++--- lib/unistd.in.h | 16 ++++++++++++++-- m4/symlinkat.m4 | 35 ++++++++++++++++++++++++++++++++++- m4/unistd_h.m4 | 1 + modules/symlinkat | 3 ++- modules/unistd | 1 + 8 files changed, 88 insertions(+), 7 deletions(-)
diff --git a/ChangeLog b/ChangeLog index e012f3a..23234b7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,17 @@ 2014-10-18 Paul Eggert <egg...@cs.ucla.edu> + symlinkat: port to AIX 7.1 + * doc/posix-functions/symlinkat.texi (symlinkat): + Mention AIX porting problem. + * lib/symlinkat.c: Always include errno.h. + (rpl_symlinkat) [HAVE_SYMLINKAT]: New function. + * lib/unistd.in.h (symlinkat): Add replacement machinery. + * m4/symlinkat.m4 (gl_FUNC_SYMLINKAT): Check symlinkat behavior. + * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Add REPLACE_SYMLINKAT. + * modules/symlinkat (Depends-on): Add fstatat if REPLACE_SYMLINKAT. + (configure.ac): Also compile replacement if REPLACE_SYMLINKAT. + * modules/unistd (unistd.h): Substitute REPLACE_SYMLINKAT. + readlinkat: port to AIX 7.1 * doc/posix-functions/readlink.texi (readlink): * doc/posix-functions/readlinkat.texi (readlinkat): diff --git a/doc/posix-functions/symlinkat.texi b/doc/posix-functions/symlinkat.texi index 27ab3ae..7c3e39a 100644 --- a/doc/posix-functions/symlinkat.texi +++ b/doc/posix-functions/symlinkat.texi @@ -9,6 +9,10 @@ Gnulib module: symlinkat Portability problems fixed by Gnulib: @itemize @item +On some systems, @code{symlinkat(value, fd, "name/")} mistakenly creates a +symlink: +AIX 7.1. +@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, 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. diff --git a/lib/symlinkat.c b/lib/symlinkat.c index 26a88f9..9797f46 100644 --- a/lib/symlinkat.c +++ b/lib/symlinkat.c @@ -19,13 +19,30 @@ #include <config.h> #include <unistd.h> +#include <errno.h> -#if !HAVE_SYMLINK +#if HAVE_SYMLINKAT +# undef symlinkat + +/* Create a symlink, but reject trailing slash. */ +int +rpl_symlinkat (char const *contents, int fd, char const *name) +{ + size_t len = strlen (name); + if (len && name[len - 1] == '/') + { + struct stat st; + if (fstatat (fd, name, &st, 0) == 0) + errno = EEXIST; + return -1; + } + return symlinkat (contents, fd, name); +} + +#elif !HAVE_SYMLINK /* Mingw lacks symlink, and it is more efficient to provide a trivial wrapper than to go through at-func.c to call rpl_symlink. */ -# include <errno.h> - int symlinkat (char const *path1 _GL_UNUSED, int fd _GL_UNUSED, char const *path2 _GL_UNUSED) diff --git a/lib/unistd.in.h b/lib/unistd.in.h index cae779d..bfa9578 100644 --- a/lib/unistd.in.h +++ b/lib/unistd.in.h @@ -1418,13 +1418,25 @@ _GL_WARN_ON_USE (symlink, "symlink is not portable - " #if @GNULIB_SYMLINKAT@ -# if !@HAVE_SYMLINKAT@ +# if @REPLACE_SYMLINKAT@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef symlinkat +# define symlinkat rpl_symlinkat +# endif +_GL_FUNCDECL_RPL (symlinkat, int, + (char const *contents, int fd, char const *file) + _GL_ARG_NONNULL ((1, 3))); +_GL_CXXALIAS_RPL (symlinkat, int, + (char const *contents, int fd, char const *file)); +# else +# if !@HAVE_SYMLINKAT@ _GL_FUNCDECL_SYS (symlinkat, int, (char const *contents, int fd, char const *file) _GL_ARG_NONNULL ((1, 3))); -# endif +# endif _GL_CXXALIAS_SYS (symlinkat, int, (char const *contents, int fd, char const *file)); +# endif _GL_CXXALIASWARN (symlinkat); #elif defined GNULIB_POSIXCHECK # undef symlinkat diff --git a/m4/symlinkat.m4 b/m4/symlinkat.m4 index db7ad48..21648bf 100644 --- a/m4/symlinkat.m4 +++ b/m4/symlinkat.m4 @@ -1,4 +1,4 @@ -# serial 5 +# serial 6 # See if we need to provide symlinkat replacement. dnl Copyright (C) 2009-2014 Free Software Foundation, Inc. @@ -16,5 +16,38 @@ AC_DEFUN([gl_FUNC_SYMLINKAT], AC_CHECK_FUNCS_ONCE([symlinkat]) if test $ac_cv_func_symlinkat = no; then HAVE_SYMLINKAT=0 + else + AC_CACHE_CHECK([whether symlinkat handles trailing slash correctly], + [gl_cv_func_symlinkat_works], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include <fcntl.h> + #include <unistd.h> + ]], + [[int result = 0; + if (!symlinkat ("a", AT_FDCWD, "conftest.link/")) + result |= 1; + if (symlinkat ("conftest.f", AT_FDCWD, "conftest.lnk2")) + result |= 2; + else if (!symlinkat ("a", AT_FDCWD, "conftest.lnk2/")) + result |= 4; + return result; + ]])], + [gl_cv_func_symlinkat_works=yes], + [gl_cv_func_symlinkat_works=no], + [case "$host_os" in + # Guess yes on glibc systems. + *-gnu*) gl_cv_func_symlinkat_works="guessing yes" ;; + # If we don't know, assume the worst. + *) gl_cv_func_symlinkat_works="guessing no" ;; + esac + ]) + rm -f conftest.f conftest.link conftest.lnk2]) + case "$gl_cv_func_symlinkat_works" in + *yes) ;; + *) + REPLACE_SYMLINKAT=1 + ;; + esac fi ]) diff --git a/m4/unistd_h.m4 b/m4/unistd_h.m4 index 6d217d6..d7346a0 100644 --- a/m4/unistd_h.m4 +++ b/m4/unistd_h.m4 @@ -177,6 +177,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS], REPLACE_RMDIR=0; AC_SUBST([REPLACE_RMDIR]) REPLACE_SLEEP=0; AC_SUBST([REPLACE_SLEEP]) REPLACE_SYMLINK=0; AC_SUBST([REPLACE_SYMLINK]) + REPLACE_SYMLINKAT=0; AC_SUBST([REPLACE_SYMLINKAT]) REPLACE_TTYNAME_R=0; AC_SUBST([REPLACE_TTYNAME_R]) REPLACE_UNLINK=0; AC_SUBST([REPLACE_UNLINK]) REPLACE_UNLINKAT=0; AC_SUBST([REPLACE_UNLINKAT]) diff --git a/modules/symlinkat b/modules/symlinkat index f5d712d..3d1f2ac 100644 --- a/modules/symlinkat +++ b/modules/symlinkat @@ -18,10 +18,11 @@ openat-die [test $HAVE_SYMLINKAT = 0] openat-h [test $HAVE_SYMLINKAT = 0] save-cwd [test $HAVE_SYMLINKAT = 0] symlink [test $HAVE_SYMLINKAT = 0] +fstatat [test $REPLACE_SYMLINKAT = 1] configure.ac: gl_FUNC_SYMLINKAT -if test $HAVE_SYMLINKAT = 0; then +if test $HAVE_SYMLINKAT = 0 || test $REPLACE_SYMLINKAT = 1; then AC_LIBOBJ([symlinkat]) fi gl_UNISTD_MODULE_INDICATOR([symlinkat]) diff --git a/modules/unistd b/modules/unistd index 0bbeb84..1619509 100644 --- a/modules/unistd +++ b/modules/unistd @@ -154,6 +154,7 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H -e 's|@''REPLACE_RMDIR''@|$(REPLACE_RMDIR)|g' \ -e 's|@''REPLACE_SLEEP''@|$(REPLACE_SLEEP)|g' \ -e 's|@''REPLACE_SYMLINK''@|$(REPLACE_SYMLINK)|g' \ + -e 's|@''REPLACE_SYMLINKAT''@|$(REPLACE_SYMLINKAT)|g' \ -e 's|@''REPLACE_TTYNAME_R''@|$(REPLACE_TTYNAME_R)|g' \ -e 's|@''REPLACE_UNLINK''@|$(REPLACE_UNLINK)|g' \ -e 's|@''REPLACE_UNLINKAT''@|$(REPLACE_UNLINKAT)|g' \ -- 1.9.3