changeset 12094:67458384fb3f

rename: fix Solaris 10 bug rename("file","name/") mistakenly succeeded. But since Solaris 10 already obeys POSIX behavior on rename("link/","name"), we avoid blindly forcing GNU behavior of rejecting symlinks with trailing slash. * m4/rename.m4 (gl_FUNC_RENAME): Detect Solaris bug. * lib/rename.c (rpl_rename): Don't cripple POSIX behavior if this was the only bug. Signed-off-by: Eric Blake <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Wed, 30 Sep 2009 21:57:58 -0600
parents b07a0a61b0c1
children 724dd32f13f7
files ChangeLog lib/rename.c m4/rename.m4
diffstat 3 files changed, 57 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2009-10-02  Eric Blake  <ebb9@byu.net>
 
+	rename: fix Solaris 10 bug
+	* m4/rename.m4 (gl_FUNC_RENAME): Detect Solaris bug.
+	* lib/rename.c (rpl_rename): Don't cripple POSIX behavior if this
+	was the only bug.
+
 	rename: fix Solaris 9 bug
 	* lib/rename.c (rpl_rename): Rewrite to recognize trailing slash
 	on non-directory.  Avoid calling exit.
--- a/lib/rename.c
+++ b/lib/rename.c
@@ -136,7 +136,7 @@
 
 # if RENAME_DEST_EXISTS_BUG
 #  error Please report your platform and this message to bug-gnulib@gnu.org.
-# elif RENAME_TRAILING_SLASH_BUG
+# elif RENAME_TRAILING_SLASH_SOURCE_BUG || RENAME_TRAILING_SLASH_DEST_BUG
 
 #  include <errno.h>
 #  include <stdio.h>
@@ -192,10 +192,24 @@
       return -1;
     }
 
-  /* If stripping the trailing slashes changes from a directory to a
-     symlink, follow the GNU behavior of rejecting the rename.
-     Technically, we could follow the POSIX behavior by chasing a
-     readlink trail, but that is counter-intuitive and harder.  */
+#  if RENAME_TRAILING_SLASH_SOURCE_BUG
+  /* If the only bug was that a trailing slash was allowed on a
+     non-existing file destination, as in Solaris 10, then we've
+     already covered that situation.  But if there is any problem with
+     a trailing slash on an existing source or destination, as in
+     Solaris 9, then we must strip the offending slash and check that
+     we have not encountered a symlink instead of a directory.
+
+     Stripping a trailing slash interferes with POSIX semantics, where
+     rename behavior on a symlink with a trailing slash operates on
+     the corresponding target directory.  We prefer the GNU semantics
+     of rejecting any use of a symlink with trailing slash, but do not
+     enforce them, since Solaris 10 is able to obey POSIX semantics
+     and there might be clients expecting it, as counter-intuitive as
+     those semantics are.
+
+     Technically, we could also follow the POSIX behavior by chasing a
+     readlink trail, but that is harder to implement.  */
   if (src_slash)
     {
       src_temp = strdup (src);
@@ -234,6 +248,8 @@
       else if (S_ISLNK (dst_st.st_mode))
         goto out;
     }
+#  endif /* RENAME_TRAILING_SLASH_SOURCE_BUG */
+
   ret_val = rename (src_temp, dst_temp);
   rename_errno = errno;
  out:
@@ -244,5 +260,5 @@
   errno = rename_errno;
   return ret_val;
 }
-# endif /* RENAME_TRAILING_SLASH_BUG */
+# endif /* RENAME_TRAILING_SLASH_*_BUG */
 #endif /* ! W32 platform */
--- a/m4/rename.m4
+++ b/m4/rename.m4
@@ -1,4 +1,4 @@
-# serial 16
+# serial 17
 
 # Copyright (C) 2001, 2003, 2005, 2006, 2009 Free Software Foundation, Inc.
 # This file is free software; the Free Software Foundation
@@ -18,8 +18,36 @@
   AC_REQUIRE([AC_CANONICAL_HOST])
   AC_REQUIRE([gl_STDIO_H_DEFAULTS])
 
+  dnl Solaris 10 mistakenly allows rename("file","name/").
+  dnl This particular condition can be worked around without stripping
+  dnl trailing slash.
+  AC_CACHE_CHECK([whether rename honors trailing slash on destination],
+    [gl_cv_func_rename_slash_dst_works],
+    [rm -rf conftest.f conftest.f1
+    touch conftest.f ||
+      AC_MSG_ERROR([cannot create temporary files])
+    AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#       include <stdio.h>
+#       include <stdlib.h>
+]], [return !rename ("conftest.f", "conftest.f1/");])],
+      [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
+  ])
+  if test "x$gl_cv_func_rename_slash_dst_works" != xyes; then
+    AC_LIBOBJ([rename])
+    REPLACE_RENAME=1
+    AC_DEFINE([RENAME_TRAILING_SLASH_DEST_BUG], [1],
+      [Define if rename does not correctly handle slashes on the destination
+       argument, such as on Solaris 10.])
+  fi
+
   dnl SunOS 4.1.1_U1 mistakenly forbids rename("dir/","name").
   dnl Solaris 9 mistakenly allows rename("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
@@ -39,7 +67,7 @@
   if test "x$gl_cv_func_rename_slash_src_works" != xyes; then
     AC_LIBOBJ([rename])
     REPLACE_RENAME=1
-    AC_DEFINE([RENAME_TRAILING_SLASH_BUG], [1],
+    AC_DEFINE([RENAME_TRAILING_SLASH_SOURCE_BUG], [1],
       [Define if rename does not correctly handle slashes on the source
        argument, such as on Solaris 9 or cygwin 1.5.])
   fi