Skip to content

Commit 870ce40

Browse files
kbleesdscho
authored andcommitted
Win32: factor out retry logic
The retry pattern is duplicated in three places. It also seems to be too hard to use: mingw_unlink() and mingw_rmdir() duplicate the code to retry, and both of them do so incompletely. They also do not restore errno if the user answers 'no'. Introduce a retry_ask_yes_no() helper function that handles retry with small delay, asking the user, and restoring errno. mingw_unlink: include _wchmod in the retry loop (which may fail if the file is locked exclusively). mingw_rmdir: include special error handling in the retry loop. Signed-off-by: Karsten Blees <[email protected]>
1 parent 8c4c76b commit 870ce40

File tree

1 file changed

+43
-55
lines changed

1 file changed

+43
-55
lines changed

compat/mingw.c

Lines changed: 43 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88

99
#define HCAST(type, handle) ((type)(intptr_t)handle)
1010

11-
static const int delay[] = { 0, 1, 10, 20, 40 };
12-
1311
int err_win_to_posix(DWORD winerr)
1412
{
1513
int error = ENOSYS;
@@ -172,15 +170,12 @@ static int read_yes_no_answer(void)
172170
return -1;
173171
}
174172

175-
static int ask_yes_no_if_possible(const char *format, ...)
173+
static int ask_yes_no_if_possible(const char *format, va_list args)
176174
{
177175
char question[4096];
178176
const char *retry_hook[] = { NULL, NULL, NULL };
179-
va_list args;
180177

181-
va_start(args, format);
182178
vsnprintf(question, sizeof(question), format, args);
183-
va_end(args);
184179

185180
if ((retry_hook[0] = mingw_getenv("GIT_ASK_YESNO"))) {
186181
retry_hook[1] = question;
@@ -202,33 +197,48 @@ static int ask_yes_no_if_possible(const char *format, ...)
202197
}
203198
}
204199

200+
static int retry_ask_yes_no(int *tries, const char *format, ...)
201+
{
202+
static const int delay[] = { 0, 1, 10, 20, 40 };
203+
va_list args;
204+
int result, saved_errno = errno;
205+
206+
if ((*tries) < ARRAY_SIZE(delay)) {
207+
/*
208+
* We assume that some other process had the file open at the wrong
209+
* moment and retry. In order to give the other process a higher
210+
* chance to complete its operation, we give up our time slice now.
211+
* If we have to retry again, we do sleep a bit.
212+
*/
213+
Sleep(delay[*tries]);
214+
(*tries)++;
215+
return 1;
216+
}
217+
218+
va_start(args, format);
219+
result = ask_yes_no_if_possible(format, args);
220+
va_end(args);
221+
errno = saved_errno;
222+
return result;
223+
}
224+
205225
int mingw_unlink(const char *pathname)
206226
{
207-
int ret, tries = 0;
227+
int tries = 0;
208228
wchar_t wpathname[MAX_LONG_PATH];
209229
if (xutftowcs_long_path(wpathname, pathname) < 0)
210230
return -1;
211231

212-
/* read-only files cannot be removed */
213-
_wchmod(wpathname, 0666);
214-
while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
232+
do {
233+
/* read-only files cannot be removed */
234+
_wchmod(wpathname, 0666);
235+
if (!_wunlink(wpathname))
236+
return 0;
215237
if (!is_file_in_use_error(GetLastError()))
216238
break;
217-
/*
218-
* We assume that some other process had the source or
219-
* destination file open at the wrong moment and retry.
220-
* In order to give the other process a higher chance to
221-
* complete its operation, we give up our time slice now.
222-
* If we have to retry again, we do sleep a bit.
223-
*/
224-
Sleep(delay[tries]);
225-
tries++;
226-
}
227-
while (ret == -1 && is_file_in_use_error(GetLastError()) &&
228-
ask_yes_no_if_possible("Unlink of file '%s' failed. "
229-
"Should I try again?", pathname))
230-
ret = _wunlink(wpathname);
231-
return ret;
239+
} while (retry_ask_yes_no(&tries, "Unlink of file '%s' failed. "
240+
"Should I try again?", pathname));
241+
return -1;
232242
}
233243

234244
static int is_dir_empty(const wchar_t *wpath)
@@ -255,12 +265,14 @@ static int is_dir_empty(const wchar_t *wpath)
255265

256266
int mingw_rmdir(const char *pathname)
257267
{
258-
int ret, tries = 0;
268+
int tries = 0;
259269
wchar_t wpathname[MAX_LONG_PATH];
260270
if (xutftowcs_long_path(wpathname, pathname) < 0)
261271
return -1;
262272

263-
while ((ret = _wrmdir(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
273+
do {
274+
if (!_wrmdir(wpathname))
275+
return 0;
264276
if (!is_file_in_use_error(GetLastError()))
265277
errno = err_win_to_posix(GetLastError());
266278
if (errno != EACCES)
@@ -269,21 +281,9 @@ int mingw_rmdir(const char *pathname)
269281
errno = ENOTEMPTY;
270282
break;
271283
}
272-
/*
273-
* We assume that some other process had the source or
274-
* destination file open at the wrong moment and retry.
275-
* In order to give the other process a higher chance to
276-
* complete its operation, we give up our time slice now.
277-
* If we have to retry again, we do sleep a bit.
278-
*/
279-
Sleep(delay[tries]);
280-
tries++;
281-
}
282-
while (ret == -1 && errno == EACCES && is_file_in_use_error(GetLastError()) &&
283-
ask_yes_no_if_possible("Deletion of directory '%s' failed. "
284-
"Should I try again?", pathname))
285-
ret = _wrmdir(wpathname);
286-
return ret;
284+
} while (retry_ask_yes_no(&tries, "Deletion of directory '%s' failed. "
285+
"Should I try again?", pathname));
286+
return -1;
287287
}
288288

289289
static inline int needs_hiding(const char *path)
@@ -1776,20 +1776,8 @@ int mingw_rename(const char *pold, const char *pnew)
17761776
SetFileAttributesW(wpnew, attrs);
17771777
}
17781778
}
1779-
if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
1780-
/*
1781-
* We assume that some other process had the source or
1782-
* destination file open at the wrong moment and retry.
1783-
* In order to give the other process a higher chance to
1784-
* complete its operation, we give up our time slice now.
1785-
* If we have to retry again, we do sleep a bit.
1786-
*/
1787-
Sleep(delay[tries]);
1788-
tries++;
1789-
goto repeat;
1790-
}
17911779
if (gle == ERROR_ACCESS_DENIED &&
1792-
ask_yes_no_if_possible("Rename from '%s' to '%s' failed. "
1780+
retry_ask_yes_no(&tries, "Rename from '%s' to '%s' failed. "
17931781
"Should I try again?", pold, pnew))
17941782
goto repeat;
17951783

0 commit comments

Comments
 (0)