Mercurial > hg > octave-lyh > gnulib-hg
changeset 12100:8e81b30aa8b7
renameat: fix Solaris bugs
renameat(fd,"file",fd,"name/") failed, just like rename.
* m4/renameat.m4 (gl_FUNC_RENAMEAT): Replace renameat if rename
needed fixing.
* m4/stdio_h.m4 (gl_STDIO_H_DEFAULTS): New witness.
* modules/stdio (Makefile.am): Substitute it.
* lib/stdio.in.h (renameat): Declare replacement.
* lib/renameat.c (rpl_renameat): Implement fix.
Signed-off-by: Eric Blake <ebb9@byu.net>
author | Eric Blake <ebb9@byu.net> |
---|---|
date | Thu, 01 Oct 2009 15:31:32 -0600 |
parents | 01c66cf797b5 |
children | 6e6a73b73bcd |
files | ChangeLog lib/renameat.c lib/stdio.in.h m4/renameat.m4 m4/stdio_h.m4 modules/stdio |
diffstat | 6 files changed, 145 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2009-10-02 Eric Blake <ebb9@byu.net> + renameat: fix Solaris bugs + * m4/renameat.m4 (gl_FUNC_RENAMEAT): Replace renameat if rename + needed fixing. + * m4/stdio_h.m4 (gl_STDIO_H_DEFAULTS): New witness. + * modules/stdio (Makefile.am): Substitute it. + * lib/stdio.in.h (renameat): Declare replacement. + * lib/renameat.c (rpl_renameat): Implement fix. + renameat: new module * modules/renameat: New file. * lib/renameat.c (renameat): Likewise.
--- a/lib/renameat.c +++ b/lib/renameat.c @@ -20,7 +20,127 @@ #include <stdio.h> -#include "openat-priv.h" +#if HAVE_RENAMEAT + +# include <errno.h> +# include <stdbool.h> +# include <stdlib.h> +# include <string.h> +# include <sys/stat.h> + +# include "dirname.h" +# include "openat.h" + +# undef renameat + +/* renameat does not honor trailing / on Solaris 10. Solve it in a + similar manner to rename. No need to worry about bugs not present + on Solaris, since all other systems either lack renameat or honor + trailing slash correctly. */ + +int +rpl_renameat (int fd1, char const *src, int fd2, char const *dst) +{ + size_t src_len = strlen (src); + size_t dst_len = strlen (dst); + char *src_temp = (char *) src; + char *dst_temp = (char *) dst; + bool src_slash; + bool dst_slash; + int ret_val = -1; + int rename_errno = ENOTDIR; + struct stat src_st; + struct stat dst_st; + + /* Let strace see any ENOENT failure. */ + if (!src_len || !dst_len) + return renameat (fd1, src, fd2, dst); + + src_slash = src[src_len - 1] == '/'; + dst_slash = dst[dst_len - 1] == '/'; + if (!src_slash && !dst_slash) + return renameat (fd1, src, fd2, dst); + + /* Presence of a trailing slash requires directory semantics. If + the source does not exist, or if the destination cannot be turned + into a directory, give up now. Otherwise, strip trailing slashes + before calling rename. */ + if (lstatat (fd1, src, &src_st)) + return -1; + if (lstatat (fd2, dst, &dst_st)) + { + if (errno != ENOENT || !S_ISDIR (src_st.st_mode)) + return -1; + } + else if (!S_ISDIR (dst_st.st_mode)) + { + errno = ENOTDIR; + return -1; + } + else if (!S_ISDIR (src_st.st_mode)) + { + errno = EISDIR; + return -1; + } + +# if RENAME_TRAILING_SLASH_SOURCE_BUG + /* See the lengthy comment in rename.c why Solaris 9 is forced to + GNU behavior, while Solaris 10 is left with POSIX behavior, + regarding symlinks with trailing slash. */ + if (src_slash) + { + src_temp = strdup (src); + if (!src_temp) + { + /* Rather than rely on strdup-posix, we set errno ourselves. */ + rename_errno = ENOMEM; + goto out; + } + strip_trailing_slashes (src_temp); + if (lstatat (fd1, src_temp, &src_st)) + { + rename_errno = errno; + goto out; + } + if (S_ISLNK (src_st.st_mode)) + goto out; + } + if (dst_slash) + { + dst_temp = strdup (dst); + if (!dst_temp) + { + rename_errno = ENOMEM; + goto out; + } + strip_trailing_slashes (dst_temp); + if (lstatat (fd2, dst_temp, &dst_st)) + { + if (errno != ENOENT) + { + rename_errno = errno; + goto out; + } + } + else if (S_ISLNK (dst_st.st_mode)) + goto out; + } +# endif /* RENAME_TRAILING_SLASH_SOURCE_BUG */ + + ret_val = renameat (fd1, src_temp, fd2, dst_temp); + rename_errno = errno; + out: + if (src_temp != src) + free (src_temp); + if (dst_temp != dst) + free (dst_temp); + errno = rename_errno; + return ret_val; +} + +#else /* !HAVE_RENAMEAT */ + +# include "openat-priv.h" /* Rename FILE1, in the directory open on descriptor FD1, to FILE2, in the directory open on descriptor FD2. If possible, do it without @@ -33,3 +153,5 @@ { return at_func2 (fd1, file1, fd2, file2, rename); } + +#endif /* !HAVE_RENAMEAT */
--- a/lib/stdio.in.h +++ b/lib/stdio.in.h @@ -445,7 +445,11 @@ #endif #if @GNULIB_RENAMEAT@ -# if !@HAVE_RENAMEAT@ +# if @REPLACE_RENAMEAT@ +# undef renameat +# define renameat rpl_renameat +# endif +# if !@HAVE_RENAMEAT@ || @REPLACE_RENAMEAT@ extern int renameat (int fd1, char const *file1, int fd2, char const *file2); # endif #elif defined GNULIB_POSIXCHECK
--- a/m4/renameat.m4 +++ b/m4/renameat.m4 @@ -1,4 +1,4 @@ -# serial 1 +# serial 2 # See if we need to provide renameat replacement. dnl Copyright (C) 2009 Free Software Foundation, Inc. @@ -19,5 +19,10 @@ HAVE_RENAMEAT=0 AC_LIBOBJ([renameat]) AC_LIBOBJ([at-func2]) + elif test $REPLACE_RENAME = 1; then + dnl Solaris 9 and 10 have the same bugs in renameat as in rename. + REPLACE_RENAMEAT=1 + AC_LIBOBJ([renameat]) + AC_LIBOBJ([at-func2]) fi ])
--- a/m4/stdio_h.m4 +++ b/m4/stdio_h.m4 @@ -1,4 +1,4 @@ -# stdio_h.m4 serial 20 +# stdio_h.m4 serial 21 dnl Copyright (C) 2007-2009 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -112,6 +112,7 @@ REPLACE_PRINTF=0; AC_SUBST([REPLACE_PRINTF]) REPLACE_REMOVE=0; AC_SUBST([REPLACE_REMOVE]) REPLACE_RENAME=0; AC_SUBST([REPLACE_RENAME]) + REPLACE_RENAMEAT=0; AC_SUBST([REPLACE_RENAMEAT]) REPLACE_SNPRINTF=0; AC_SUBST([REPLACE_SNPRINTF]) REPLACE_SPRINTF=0; AC_SUBST([REPLACE_SPRINTF]) REPLACE_STDIO_WRITE_FUNCS=0; AC_SUBST([REPLACE_STDIO_WRITE_FUNCS])
--- a/modules/stdio +++ b/modules/stdio @@ -94,6 +94,7 @@ -e 's|@''REPLACE_PRINTF''@|$(REPLACE_PRINTF)|g' \ -e 's|@''REPLACE_REMOVE''@|$(REPLACE_REMOVE)|g' \ -e 's|@''REPLACE_RENAME''@|$(REPLACE_RENAME)|g' \ + -e 's|@''REPLACE_RENAMEAT''@|$(REPLACE_RENAMEAT)|g' \ -e 's|@''REPLACE_SNPRINTF''@|$(REPLACE_SNPRINTF)|g' \ -e 's|@''REPLACE_SPRINTF''@|$(REPLACE_SPRINTF)|g' \ -e 's|@''REPLACE_STDIO_WRITE_FUNCS''@|$(REPLACE_STDIO_WRITE_FUNCS)|g' \