From: Ben Pfaff Date: Wed, 8 Apr 2009 03:41:15 +0000 (-0700) Subject: Make rename replace existing destinations on Windows. X-Git-Tag: v0.1~6009 X-Git-Url: http://erislabs.net/gitweb/?a=commitdiff_plain;h=533b27747fe3d0d67f727d4d7ba6c97f8a5b4060;p=gnulib.git Make rename replace existing destinations on Windows. --- diff --git a/ChangeLog b/ChangeLog index d762402a9..80aed98be 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2009-03-20 Ben Pfaff + + Make rename replace existing destinations on Windows. + * m4/rename.m4: Add test for Mingw. + * lib/rename.c: Add rename replacement that uses MoveFileEx with + MOVEFILE_REPLACE_EXISTING to replace existing destination files. + * doc/posix-functions/rename.texi: Document. + 2009-04-10 Bruno Haible New include file "iconveh.h". diff --git a/doc/posix-functions/rename.texi b/doc/posix-functions/rename.texi index 62b1fc8d6..aa7287a4e 100644 --- a/doc/posix-functions/rename.texi +++ b/doc/posix-functions/rename.texi @@ -12,8 +12,15 @@ Portability problems fixed by Gnulib: This function does not work when the source file name ends in a slash on some platforms: SunOS 4.1. +@item +This function will not replace an existing destination on some +platforms: +mingw. @end itemize Portability problems not fixed by Gnulib: @itemize +This function will not replace a destination that is currently opened +by any process: +mingw. @end itemize diff --git a/lib/rename.c b/lib/rename.c index 9667c39e7..b27fd9100 100644 --- a/lib/rename.c +++ b/lib/rename.c @@ -1,8 +1,9 @@ -/* Work around the bug in some systems whereby rename fails when the source - file has a trailing slash. The rename functions of SunOS 4.1.1_U1 and - mips-dec-ultrix4.4 have this bug. +/* Work around rename bugs in some systems. On SunOS 4.1.1_U1 + and mips-dec-ultrix4.4, rename fails when the source file has + a trailing slash. On mingw, rename fails when the destination + exists. - Copyright (C) 2001, 2002, 2003, 2005, 2006 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2003, 2005, 2006, 2009 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,6 +23,113 @@ #include #undef rename +#if RENAME_DEST_EXISTS_BUG +/* This replacement must come first, otherwise when cross + * compiling to Windows we will guess that it has the trailing + * slash bug and entirely miss this one. */ +#include + +#define WIN32_LEAN_AND_MEAN +#include + +/* Rename the file SRC to DST. This replacement is necessary on + Windows, on which the system rename function will not replace + an existing DST. */ +int +rpl_rename (char const *src, char const *dst) +{ + int error; + + /* MoveFileEx works if SRC is a directory without any flags, + but fails with MOVEFILE_REPLACE_EXISTING, so try without + flags first. */ + if (MoveFileEx (src, dst, 0)) + return 0; + + /* Retry with MOVEFILE_REPLACE_EXISTING if the move failed + * due to the destination already existing. */ + error = GetLastError (); + if (error == ERROR_FILE_EXISTS || error == ERROR_ALREADY_EXISTS) + { + if (MoveFileEx (src, dst, MOVEFILE_REPLACE_EXISTING)) + return 0; + + error = GetLastError (); + } + + switch (error) + { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_BAD_PATHNAME: + case ERROR_DIRECTORY: + errno = ENOENT; + break; + + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + errno = EACCES; + break; + + case ERROR_OUTOFMEMORY: + errno = ENOMEM; + break; + + case ERROR_CURRENT_DIRECTORY: + errno = EBUSY; + break; + + case ERROR_NOT_SAME_DEVICE: + errno = EXDEV; + break; + + case ERROR_WRITE_PROTECT: + errno = EROFS; + break; + + case ERROR_WRITE_FAULT: + case ERROR_READ_FAULT: + case ERROR_GEN_FAILURE: + errno = EIO; + break; + + case ERROR_HANDLE_DISK_FULL: + case ERROR_DISK_FULL: + case ERROR_DISK_TOO_FRAGMENTED: + errno = ENOSPC; + break; + + case ERROR_FILE_EXISTS: + case ERROR_ALREADY_EXISTS: + errno = EEXIST; + break; + + case ERROR_BUFFER_OVERFLOW: + case ERROR_FILENAME_EXCED_RANGE: + errno = ENAMETOOLONG; + break; + + case ERROR_INVALID_NAME: + case ERROR_DELETE_PENDING: + errno = EPERM; /* ? */ + break; + +#ifndef ERROR_FILE_TOO_LARGE +/* This value is documented but not defined in all versions of windows.h. */ +#define ERROR_FILE_TOO_LARGE 223 +#endif + case ERROR_FILE_TOO_LARGE: + errno = EFBIG; + break; + + default: + errno = EINVAL; + break; + } + + return -1; +} +#elif RENAME_TRAILING_SLASH_BUG #include #include #include @@ -54,3 +162,4 @@ rpl_rename (char const *src, char const *dst) return ret_val; } +#endif /* RENAME_TRAILING_SLASH_BUG */ diff --git a/m4/rename.m4 b/m4/rename.m4 index fa7ae8d3f..53f9ea5b7 100644 --- a/m4/rename.m4 +++ b/m4/rename.m4 @@ -1,4 +1,4 @@ -# serial 11 +# serial 12 # Copyright (C) 2001, 2003, 2005, 2006, 2009 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation @@ -15,7 +15,8 @@ dnl AC_DEFUN([gl_FUNC_RENAME], [ - AC_CACHE_CHECK([whether rename is broken], + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_CACHE_CHECK([whether rename is broken with a trailing slash], gl_cv_func_rename_trailing_slash_bug, [ rm -rf conftest.d1 conftest.d2 @@ -37,13 +38,29 @@ AC_DEFUN([gl_FUNC_RENAME], rm -rf conftest.d1 conftest.d2 ]) - if test $gl_cv_func_rename_trailing_slash_bug = yes; then + 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 + ]) + if test $gl_cv_func_rename_trailing_slash_bug = yes || + test $gl_cv_func_rename_dest_exists_bug = yes; then AC_LIBOBJ([rename]) AC_DEFINE([rename], [rpl_rename], [Define to rpl_rename if the replacement function should be used.]) - AC_DEFINE([RENAME_TRAILING_SLASH_BUG], [1], - [Define if rename does not work for source file names with a trailing - slash, like the one from SunOS 4.1.1_U1.]) + if test $gl_cv_func_rename_trailing_slash_bug; then + AC_DEFINE([RENAME_TRAILING_SLASH_BUG], [1], + [Define if rename does not work for source file names with a trailing + slash, like the one from SunOS 4.1.1_U1.]) + fi + if test $gl_cv_func_rename_dest_exists_bug; then + AC_DEFINE([RENAME_DEST_EXISTS_BUG], [1], + [Define if rename does not work when the destination file exists, + as on Windows.]) + fi gl_PREREQ_RENAME fi ])