rename: detect FreeBSD bug
authorEric Blake <ebb9@byu.net>
Mon, 9 Nov 2009 01:11:50 +0000 (18:11 -0700)
committerIan Beckwith <ianb@erislabs.net>
Sun, 15 Nov 2009 02:49:14 +0000 (02:49 +0000)
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 <ebb9@byu.net>
(cherry picked from commit d462fe1752f26b281d2627e5e151c70341dc6d33)

ChangeLog
doc/posix-functions/rename.texi
m4/rename.m4
modules/renameat-tests
tests/test-rename.h
tests/test-renameat.c

index 57848e4..599a2ab 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2009-11-09  Eric Blake  <ebb9@byu.net>
 
+       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.
index be997aa..cd11a6d 100644 (file)
@@ -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.
index 27c9944..2654d2a 100644 (file)
@@ -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 <stdio.h>
 #       include <stdlib.h>
 ]], [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 <stdio.h>
 #       include <stdlib.h>
 ]], [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])
index 20122da..399ff08 100644 (file)
@@ -3,6 +3,7 @@ tests/test-rename.h
 tests/test-renameat.c
 
 Depends-on:
+filenamecat
 progname
 xgetcwd
 
index b4f8c12..63ec8ca 100644 (file)
@@ -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);
index 88c0cb0..d43af37 100644 (file)
@@ -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);