From d462fe1752f26b281d2627e5e151c70341dc6d33 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Sun, 8 Nov 2009 18:11:50 -0700 Subject: [PATCH] rename: detect FreeBSD bug rename("link-to-file/","new") mistakenly succeeded. * m4/rename.m4 (gl_FUNC_RENAME): Also detect FreeBSD bug with slash on symlink. * modules/renameat-tests (Depends-on): Add filenamecat. * tests/test-rename.h (test_rename): Allow one more errno. * tests/test-renameat.c (main): Likewise. * doc/posix-functions/rename.texi (rename): Document the bug. Signed-off-by: Eric Blake --- ChangeLog | 8 ++++++++ doc/posix-functions/rename.texi | 9 +++++++-- m4/rename.m4 | 33 ++++++++++++++++++++++++++------- modules/renameat-tests | 1 + tests/test-rename.h | 6 ++++-- tests/test-renameat.c | 3 ++- 6 files changed, 48 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 57848e469..599a2ab6a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2009-11-09 Eric Blake + rename: detect FreeBSD bug + * m4/rename.m4 (gl_FUNC_RENAME): Also detect FreeBSD bug with + slash on symlink. + * modules/renameat-tests (Depends-on): Add filenamecat. + * tests/test-rename.h (test_rename): Allow one more errno. + * tests/test-renameat.c (main): Likewise. + * doc/posix-functions/rename.texi (rename): Document the bug. + open: detect FreeBSD bug * m4/open.m4 (gl_FUNC_OPEN): Also detect FreeBSD bug with slash on symlink. diff --git a/doc/posix-functions/rename.texi b/doc/posix-functions/rename.texi index be997aae1..cd11a6de7 100644 --- a/doc/posix-functions/rename.texi +++ b/doc/posix-functions/rename.texi @@ -13,10 +13,15 @@ This function does not allow trailing slashes when creating a destination directory, as in @code{rename("dir","new/")}: NetBSD 1.6. @item -This function does not reject trailing slashes on non-directories on -some platforms, as in @code{rename("file","new/")}: +This function does not reject trailing slashes on the destination for +non-directories on some platforms, as in @code{rename("file","new/")}: Solaris 10, Cygwin 1.5.x, mingw. @item +This function does not reject trailing slashes on symlinks to +non-directories on some platforms, as in +@code{rename("link-to-file/","f")}: +FreeBSD 7.2. +@item This function ignores trailing slashes on symlinks on some platforms, such that @code{rename("link/","new")} corrupts @file{link}: Solaris 9. diff --git a/m4/rename.m4 b/m4/rename.m4 index 27c9944c6..2654d2a84 100644 --- a/m4/rename.m4 +++ b/m4/rename.m4 @@ -1,4 +1,4 @@ -# serial 20 +# serial 21 # Copyright (C) 2001, 2003, 2005, 2006, 2009 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation @@ -17,28 +17,38 @@ AC_DEFUN([gl_FUNC_RENAME], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([gl_STDIO_H_DEFAULTS]) + AC_CHECK_FUNCS_ONCE([lstat]) dnl Solaris 10 mistakenly allows rename("file","name/"). dnl NetBSD 1.6 mistakenly forbids rename("dir","name/"). + dnl FreeBSD 7.2 mistakenly allows rename("file","link-to-file/"). dnl The Solaris bug can be worked around without stripping dnl trailing slash, while the NetBSD bug requires stripping; dnl the two conditions can be distinguished by whether hard dnl links are also broken. AC_CACHE_CHECK([whether rename honors trailing slash on destination], [gl_cv_func_rename_slash_dst_works], - [rm -rf conftest.f conftest.f1 conftest.d1 conftest.d2 + [rm -rf conftest.f conftest.f1 conftest.d1 conftest.d2 conftest.lnk touch conftest.f && mkdir conftest.d1 || AC_MSG_ERROR([cannot create temporary files]) + # Assume that if we have lstat, we can also check symlinks. + if test $ac_cv_func_lstat = yes; then + ln -s conftest.f conftest.lnk + fi AC_RUN_IFELSE([AC_LANG_PROGRAM([[ # include # include ]], [if (rename ("conftest.f", "conftest.f1/") == 0) return 1; - if (rename ("conftest.d1", "conftest.d2/") != 0) return 2;])], + if (rename ("conftest.d1", "conftest.d2/") != 0) return 2; +#if HAVE_LSTAT + if (rename ("conftest.f", "conftest.lnk/") == 0) return 3; +#endif + ])], [gl_cv_func_rename_slash_dst_works=yes], [gl_cv_func_rename_slash_dst_works=no], dnl When crosscompiling, assume rename is broken. [gl_cv_func_rename_slash_dst_works="guessing no"]) - rm -rf conftest.f conftest.f1 conftest.d1 conftest.d2 + rm -rf conftest.f conftest.f1 conftest.d1 conftest.d2 conftest.lnk ]) if test "x$gl_cv_func_rename_slash_dst_works" != xyes; then AC_LIBOBJ([rename]) @@ -50,23 +60,32 @@ AC_DEFUN([gl_FUNC_RENAME], dnl SunOS 4.1.1_U1 mistakenly forbids rename("dir/","name"). dnl Solaris 9 mistakenly allows rename("file/","name"). + dnl FreeBSD 7.2 mistakenly allows rename("link-to-file/","name"). dnl These bugs require stripping trailing slash to avoid corrupting dnl symlinks with a trailing slash. AC_CACHE_CHECK([whether rename honors trailing slash on source], [gl_cv_func_rename_slash_src_works], - [rm -rf conftest.f conftest.d1 conftest.d2 + [rm -rf conftest.f conftest.d1 conftest.d2 conftest.lnk touch conftest.f && mkdir conftest.d1 || AC_MSG_ERROR([cannot create temporary files]) + # Assume that if we have lstat, we can also check symlinks. + if test $ac_cv_func_lstat = yes; then + ln -s conftest.f conftest.lnk + fi AC_RUN_IFELSE([AC_LANG_PROGRAM([[ # include # include ]], [if (rename ("conftest.f/", "conftest.d2") == 0) return 1; - if (rename ("conftest.d1/", "conftest.d2") != 0) return 2;])], + if (rename ("conftest.d1/", "conftest.d2") != 0) return 2; +#if HAVE_LSTAT + if (rename ("conftest.lnk/", "conftest.f") == 0) return 3; +#endif + ])], [gl_cv_func_rename_slash_src_works=yes], [gl_cv_func_rename_slash_src_works=no], dnl When crosscompiling, assume rename is broken. [gl_cv_func_rename_slash_src_works="guessing no"]) - rm -rf conftest.f conftest.d1 conftest.d2 + rm -rf conftest.f conftest.d1 conftest.d2 conftest.lnk ]) if test "x$gl_cv_func_rename_slash_src_works" != xyes; then AC_LIBOBJ([rename]) diff --git a/modules/renameat-tests b/modules/renameat-tests index 20122dad6..399ff08f3 100644 --- a/modules/renameat-tests +++ b/modules/renameat-tests @@ -3,6 +3,7 @@ tests/test-rename.h tests/test-renameat.c Depends-on: +filenamecat progname xgetcwd diff --git a/tests/test-rename.h b/tests/test-rename.h index b4f8c1243..63ec8ca97 100644 --- a/tests/test-rename.h +++ b/tests/test-rename.h @@ -138,7 +138,8 @@ test_rename (int (*func) (char const *, char const *), bool print) ASSERT (mkdir (BASE "dir", 0700) == 0); errno = 0; ASSERT (func (BASE "dir2", BASE "dir/.") == -1); - ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR); + ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR + || errno == ENOTEMPTY); errno = 0; ASSERT (func (BASE "dir2/.", BASE "dir") == -1); ASSERT (errno == EINVAL || errno == EBUSY); @@ -149,7 +150,8 @@ test_rename (int (*func) (char const *, char const *), bool print) ASSERT (mkdir (BASE "dir", 0700) == 0); errno = 0; ASSERT (func (BASE "dir2", BASE "dir/.//") == -1); - ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR); + ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR + || errno == ENOTEMPTY); errno = 0; ASSERT (func (BASE "dir2/.//", BASE "dir") == -1); ASSERT (errno == EINVAL || errno == EBUSY); diff --git a/tests/test-renameat.c b/tests/test-renameat.c index 88c0cb08e..d43af37d6 100644 --- a/tests/test-renameat.c +++ b/tests/test-renameat.c @@ -134,7 +134,8 @@ main (void) ASSERT (unlink (BASE "sub2/file") == 0); errno = 0; ASSERT (renameat (dfd, BASE "sub2", dfd, BASE "sub1/.") == -1); - ASSERT (errno == EINVAL || errno == EISDIR || errno == EBUSY); + ASSERT (errno == EINVAL || errno == EISDIR || errno == EBUSY + || errno == ENOTEMPTY); errno = 0; ASSERT (renameat (dfd, BASE "sub2/.", dfd, BASE "sub1") == -1); ASSERT (errno == EINVAL || errno == EBUSY); -- 2.11.0