Windows: Work around misbehaved rename().
authorJohannes Sixt <johannes.sixt@telecom.at>
Fri, 7 Dec 2007 21:19:40 +0000 (22:19 +0100)
committerJohannes Sixt <johannes.sixt@telecom.at>
Mon, 23 Jun 2008 11:40:18 +0000 (13:40 +0200)
Windows's rename() is based on the MoveFile() API, which fails if the
destination exists. Here we work around the problem by using MoveFileEx().
Furthermore, the posixly correct error is returned if the destination is
a directory.

The implementation is still slightly incomplete, however, because of the
missing error code translation: We assume that the failure is due to
permissions.

Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>
compat/mingw.c
compat/mingw.h

index 0e1ddbe4dff977c4141df925940c90bbbe7f7e24..c6a5c1b2184643a84ac2fc9dde619f89f245386a 100644 (file)
@@ -73,6 +73,31 @@ char *mingw_getcwd(char *pointer, int len)
        return ret;
 }
 
+#undef rename
+int mingw_rename(const char *pold, const char *pnew)
+{
+       /*
+        * Try native rename() first to get errno right.
+        * It is based on MoveFile(), which cannot overwrite existing files.
+        */
+       if (!rename(pold, pnew))
+               return 0;
+       if (errno != EEXIST)
+               return -1;
+       if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+               return 0;
+       /* TODO: translate more errors */
+       if (GetLastError() == ERROR_ACCESS_DENIED) {
+               DWORD attrs = GetFileAttributes(pnew);
+               if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
+                       errno = EISDIR;
+                       return -1;
+               }
+       }
+       errno = EACCES;
+       return -1;
+}
+
 struct passwd *getpwuid(int uid)
 {
        static char user_name[100];
index 95a08b4128d6d5a2017aca18b9b6de59dcbc12ea..46fd8da06e75484e8f5414bfb85b99cecd82236a 100644 (file)
@@ -151,6 +151,9 @@ int mingw_open (const char *filename, int oflags, ...);
 char *mingw_getcwd(char *pointer, int len);
 #define getcwd mingw_getcwd
 
+int mingw_rename(const char*, const char*);
+#define rename mingw_rename
+
 /*
  * git specific compatibility
  */