mingw: try resetting the read-only bit if rename fails (#4527)

With this patch, Git for Windows works as intended on mounted APFS
volumes (where renaming read-only files would fail).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin 2023-08-07 16:12:10 +02:00
commit 5cd82ea57d

View File

@ -2784,7 +2784,7 @@ int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
int mingw_rename(const char *pold, const char *pnew) int mingw_rename(const char *pold, const char *pnew)
{ {
static int supports_file_rename_info_ex = 1; static int supports_file_rename_info_ex = 1;
DWORD attrs = INVALID_FILE_ATTRIBUTES, gle; DWORD attrs = INVALID_FILE_ATTRIBUTES, gle, attrsold;
int tries = 0; int tries = 0;
wchar_t wpold[MAX_LONG_PATH], wpnew[MAX_LONG_PATH]; wchar_t wpold[MAX_LONG_PATH], wpnew[MAX_LONG_PATH];
int wpnew_len; int wpnew_len;
@ -2876,11 +2876,24 @@ repeat:
gle = GetLastError(); gle = GetLastError();
} }
if (gle == ERROR_ACCESS_DENIED && is_inside_windows_container()) { if (gle == ERROR_ACCESS_DENIED) {
/* Fall back to copy to destination & remove source */ if (is_inside_windows_container()) {
if (CopyFileW(wpold, wpnew, FALSE) && !mingw_unlink(pold)) /* Fall back to copy to destination & remove source */
return 0; if (CopyFileW(wpold, wpnew, FALSE) && !mingw_unlink(pold, 1))
gle = GetLastError(); return 0;
gle = GetLastError();
} else if ((attrsold = GetFileAttributesW(wpold)) & FILE_ATTRIBUTE_READONLY) {
/* if file is read-only, change and retry */
SetFileAttributesW(wpold, attrsold & ~FILE_ATTRIBUTE_READONLY);
if (MoveFileExW(wpold, wpnew,
MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED)) {
SetFileAttributesW(wpnew, attrsold);
return 0;
}
gle = GetLastError();
/* revert attribute change on failure */
SetFileAttributesW(wpold, attrsold);
}
} }
/* revert file attributes on failure */ /* revert file attributes on failure */