Mercurial > hg > octave-lojdl > gnulib-hg
changeset 12095:724dd32f13f7
rename: fix cygwin 1.5.x bugs
On cygwin 1.5.x, rename("dir","file") mistakenly succeeded.
rename("hard1","hard2") mistakenly reduced the hard link count,
such that "hard1" disappears once "hard2" is unlinked.
* m4/rename.m4 (gl_FUNC_RENAME): Detect cygwin bugs.
* lib/rename.c (rpl_rename): Work around them.
* modules/rename (Depends-on): Add same-inode.
author | Eric Blake <ebb9@byu.net> |
---|---|
date | Tue, 29 Sep 2009 16:42:59 -0600 |
parents | 67458384fb3f |
children | 1f43035b0900 |
files | ChangeLog lib/rename.c m4/rename.m4 modules/rename |
diffstat | 4 files changed, 80 insertions(+), 31 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2009-10-02 Eric Blake <ebb9@byu.net> + rename: fix cygwin 1.5.x bugs + * m4/rename.m4 (gl_FUNC_RENAME): Detect cygwin bugs. + * lib/rename.c (rpl_rename): Work around them. + * modules/rename (Depends-on): Add same-inode. + 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
--- a/lib/rename.c +++ b/lib/rename.c @@ -134,17 +134,14 @@ #else /* ! W32 platform */ -# if RENAME_DEST_EXISTS_BUG -# error Please report your platform and this message to bug-gnulib@gnu.org. -# elif RENAME_TRAILING_SLASH_SOURCE_BUG || RENAME_TRAILING_SLASH_DEST_BUG +# include <errno.h> +# include <stdio.h> +# include <stdlib.h> +# include <string.h> +# include <sys/stat.h> -# include <errno.h> -# include <stdio.h> -# include <stdlib.h> -# include <string.h> -# include <sys/stat.h> - -# include "dirname.h" +# include "dirname.h" +# include "same-inode.h" /* Rename the file SRC to DST, fixing any trailing slash bugs. */ @@ -165,10 +162,41 @@ if (!src_len || !dst_len) return rename (src, dst); /* Let strace see the ENOENT failure. */ +# if RENAME_DEST_EXISTS_BUG + { + char *src_base = last_component (src); + char *dst_base = last_component (dst); + if (*src_base == '.') + { + size_t len = base_len (src_base); + if (len == 1 || (len == 2 && src_base[1] == '.')) + { + errno = EINVAL; + return -1; + } + } + if (*dst_base == '.') + { + size_t len = base_len (dst_base); + if (len == 1 || (len == 2 && dst_base[1] == '.')) + { + errno = EINVAL; + return -1; + } + } + } +# endif /* RENAME_DEST_EXISTS_BUG */ + src_slash = src[src_len - 1] == '/'; dst_slash = dst[dst_len - 1] == '/'; + +# if !RENAME_DEST_EXISTS_BUG + /* If there are no trailing slashes, then trust the native + implementation unless we also suspect issues with hard link + detection. */ if (!src_slash && !dst_slash) return rename (src, dst); +# endif /* !RENAME_DEST_EXISTS_BUG */ /* Presence of a trailing slash requires directory semantics. If the source does not exist, or if the destination cannot be turned @@ -178,26 +206,29 @@ return -1; if (lstat (dst, &dst_st)) { - if (errno != ENOENT || !S_ISDIR (src_st.st_mode)) + if (errno != ENOENT || (!S_ISDIR (src_st.st_mode) && dst_slash)) return -1; } - else if (!S_ISDIR (dst_st.st_mode)) + else { - errno = ENOTDIR; - return -1; - } - else if (!S_ISDIR (src_st.st_mode)) - { - errno = EISDIR; - return -1; + if (S_ISDIR (dst_st.st_mode) != S_ISDIR (src_st.st_mode)) + { + errno = S_ISDIR (dst_st.st_mode) ? EISDIR : ENOTDIR; + return -1; + } +# if RENAME_DEST_EXISTS_BUG + if (SAME_INODE (src_st, dst_st)) + return 0; +# endif /* RENAME_DEST_EXISTS_BUG */ } -# if RENAME_TRAILING_SLASH_SOURCE_BUG +# if RENAME_TRAILING_SLASH_SOURCE_BUG || RENAME_DEST_EXISTS_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 + Solaris 9, or if a directory can overwrite a symlink, as on + Cygwin 1.5, 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 @@ -248,7 +279,7 @@ else if (S_ISLNK (dst_st.st_mode)) goto out; } -# endif /* RENAME_TRAILING_SLASH_SOURCE_BUG */ +# endif /* RENAME_TRAILING_SLASH_SOURCE_BUG || RENAME_DEST_EXISTS_BUG */ ret_val = rename (src_temp, dst_temp); rename_errno = errno; @@ -260,5 +291,4 @@ errno = rename_errno; return ret_val; } -# endif /* RENAME_TRAILING_SLASH_*_BUG */ #endif /* ! W32 platform */
--- a/m4/rename.m4 +++ b/m4/rename.m4 @@ -1,4 +1,4 @@ -# serial 17 +# serial 18 # Copyright (C) 2001, 2003, 2005, 2006, 2009 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation @@ -72,14 +72,27 @@ argument, such as on Solaris 9 or cygwin 1.5.]) fi - AC_CACHE_CHECK([whether rename is broken when the destination exists], - [gl_cv_func_rename_dest_exists_bug], - [case "$host_os" in - mingw*) gl_cv_func_rename_dest_exists_bug=yes ;; - *) gl_cv_func_rename_dest_exists_bug=no ;; - esac + dnl Cygwin 1.5.x mistakenly allows rename("dir","file"). + dnl mingw mistakenly forbids rename("dir1","dir2"). + dnl These bugs require stripping trailing slash to avoid corrupting + dnl symlinks with a trailing slash. + AC_CACHE_CHECK([whether rename manages existing destinations correctly], + [gl_cv_func_rename_dest_works], + [rm -rf conftest.f conftest.d1 conftest.d2 + touch conftest.f && mkdir conftest.d1 conftest.d2 || + AC_MSG_ERROR([cannot create temporary files]) + AC_RUN_IFELSE([AC_LANG_PROGRAM([[ +# include <stdio.h> +# include <stdlib.h> +]], [if (rename ("conftest.d1", "conftest.d2") != 0) return 1; + if (rename ("conftest.d2", "conftest.f") == 0) return 2;])], + [gl_cv_func_rename_dest_works=yes], + [gl_cv_func_rename_dest_works=no], + dnl When crosscompiling, assume rename is broken. + [gl_cv_func_rename_dest_works="guessing no"]) + rm -rf conftest.f conftest.f1 conftest.d1 conftest.d2 ]) - if test $gl_cv_func_rename_dest_exists_bug = yes; then + if test "x$gl_cv_func_rename_dest_works" != xyes; then AC_LIBOBJ([rename]) REPLACE_RENAME=1 AC_DEFINE([RENAME_DEST_EXISTS_BUG], [1],