@matheusbsbs / matheus-bagliano / commits / 632f701787
Fork 0

compat/mingw.c: Teach mingw_rename() to replace read-only files

On POSIX, rename() can replace files that are not writable. On Windows, however, read-only files cannot be replaced without additional efforts: We have to make the destination writable first. Since the situations where the destination is read-only are rare, we do not make the destination writable on every invocation, but only if the first try to rename a file failed with an "access denied" error. Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Sixt committed Nov 19, 2008 at 17:25 UTC 632f70178784291bd2974e07fdcd2b8e8608f252
1 file changed +12 -3
compat/mingw.c
+12 -3
@@ -865,6 +865,8 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
865 #undef rename
866 int mingw_rename(const char *pold, const char *pnew)
867 {
868 + DWORD attrs;
869 +
870 /*
871 * Try native rename() first to get errno right.
872 * It is based on MoveFile(), which cannot overwrite existing files.
@@ -876,12 +878,19 @@ int mingw_rename(const char *pold, const char *pnew)
878 if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
879 return 0;
880 /* TODO: translate more errors */
879 - if (GetLastError() == ERROR_ACCESS_DENIED) {
880 - DWORD attrs = GetFileAttributes(pnew);
881 - if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
881 + if (GetLastError() == ERROR_ACCESS_DENIED &&
882 + (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
883 + if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
884 errno = EISDIR;
885 return -1;
886 }
887 + if ((attrs & FILE_ATTRIBUTE_READONLY) &&
888 + SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
889 + if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
890 + return 0;
891 + /* revert file attributes on failure */
892 + SetFileAttributes(pnew, attrs);
893 + }
894 }
895 errno = EACCES;
896 return -1;