Skip to content

Commit 632f701

Browse files
j6tgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 3eb91bf commit 632f701

File tree

1 file changed

+12
-3
lines changed

1 file changed

+12
-3
lines changed

compat/mingw.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,8 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
865865
#undef rename
866866
int mingw_rename(const char *pold, const char *pnew)
867867
{
868+
DWORD attrs;
869+
868870
/*
869871
* Try native rename() first to get errno right.
870872
* It is based on MoveFile(), which cannot overwrite existing files.
@@ -876,12 +878,19 @@ int mingw_rename(const char *pold, const char *pnew)
876878
if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
877879
return 0;
878880
/* 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) {
882884
errno = EISDIR;
883885
return -1;
884886
}
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+
}
885894
}
886895
errno = EACCES;
887896
return -1;

0 commit comments

Comments
 (0)