rename: fix Solaris 10 bug
authorEric Blake <ebb9@byu.net>
Thu, 1 Oct 2009 03:57:58 +0000 (21:57 -0600)
committerEric Blake <ebb9@byu.net>
Fri, 2 Oct 2009 12:07:23 +0000 (06:07 -0600)
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>
ChangeLog
lib/rename.c
m4/rename.m4

index 4b78fa0d0c086cf5229d6bc76a682e01e5b57764..8c38c9c5b7339281b451c85eb2db22c85afbf362 100644 (file)
--- 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.
index 0709759841d557c360db2ee111da033297e51309..22310be330b281b3ad80f1a5f63fbfda6a28e725 100644 (file)
@@ -136,7 +136,7 @@ rpl_rename (char const *src, char const *dst)
 
 # 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 @@ rpl_rename (char const *src, char const *dst)
       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 @@ rpl_rename (char const *src, char const *dst)
       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 @@ rpl_rename (char const *src, char const *dst)
   errno = rename_errno;
   return ret_val;
 }
-# endif /* RENAME_TRAILING_SLASH_BUG */
+# endif /* RENAME_TRAILING_SLASH_*_BUG */
 #endif /* ! W32 platform */
index 2c0d5e86f05b64e85696c4f20be2d5e411a6f8f1..04921faf58e703bace2bb3072fb014588d8b706e 100644 (file)
@@ -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_DEFUN([gl_FUNC_RENAME],
   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 @@ AC_DEFUN([gl_FUNC_RENAME],
   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