Skip to content

Commit d142e2d

Browse files
kbleesGit for Windows Build Agent
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 1940e3d commit d142e2d

File tree

1 file changed

+46
-58
lines changed

1 file changed

+46
-58
lines changed

compat/mingw.c

Lines changed: 46 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030

3131
#define HCAST(type, handle) ((type)(intptr_t)handle)
3232

33-
static const int delay[] = { 0, 1, 10, 20, 40 };
34-
3533
void open_in_gdb(void)
3634
{
3735
static struct child_process cp = CHILD_PROCESS_INIT;
@@ -207,15 +205,12 @@ static int read_yes_no_answer(void)
207205
return -1;
208206
}
209207

210-
static int ask_yes_no_if_possible(const char *format, ...)
208+
static int ask_yes_no_if_possible(const char *format, va_list args)
211209
{
212210
char question[4096];
213211
const char *retry_hook;
214-
va_list args;
215212

216-
va_start(args, format);
217213
vsnprintf(question, sizeof(question), format, args);
218-
va_end(args);
219214

220215
retry_hook = mingw_getenv("GIT_ASK_YESNO");
221216
if (retry_hook) {
@@ -240,6 +235,31 @@ static int ask_yes_no_if_possible(const char *format, ...)
240235
}
241236
}
242237

238+
static int retry_ask_yes_no(int *tries, const char *format, ...)
239+
{
240+
static const int delay[] = { 0, 1, 10, 20, 40 };
241+
va_list args;
242+
int result, saved_errno = errno;
243+
244+
if ((*tries) < ARRAY_SIZE(delay)) {
245+
/*
246+
* We assume that some other process had the file open at the wrong
247+
* moment and retry. In order to give the other process a higher
248+
* chance to complete its operation, we give up our time slice now.
249+
* If we have to retry again, we do sleep a bit.
250+
*/
251+
Sleep(delay[*tries]);
252+
(*tries)++;
253+
return 1;
254+
}
255+
256+
va_start(args, format);
257+
result = ask_yes_no_if_possible(format, args);
258+
va_end(args);
259+
errno = saved_errno;
260+
return result;
261+
}
262+
243263
/* Windows only */
244264
enum hide_dotfiles_type {
245265
HIDE_DOTFILES_FALSE = 0,
@@ -332,37 +352,27 @@ static wchar_t *normalize_ntpath(wchar_t *wbuf)
332352

333353
int mingw_unlink(const char *pathname, int handle_in_use_error)
334354
{
335-
int ret, tries = 0;
355+
int tries = 0;
336356
wchar_t wpathname[MAX_LONG_PATH];
337357
if (xutftowcs_long_path(wpathname, pathname) < 0)
338358
return -1;
339359

340360
if (DeleteFileW(wpathname))
341361
return 0;
342362

343-
/* read-only files cannot be removed */
344-
_wchmod(wpathname, 0666);
345-
while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
363+
do {
364+
/* read-only files cannot be removed */
365+
_wchmod(wpathname, 0666);
366+
if (!_wunlink(wpathname))
367+
return 0;
346368
if (!is_file_in_use_error(GetLastError()))
347369
break;
348370
if (!handle_in_use_error)
349-
return ret;
371+
return -1;
350372

351-
/*
352-
* We assume that some other process had the source or
353-
* destination file open at the wrong moment and retry.
354-
* In order to give the other process a higher chance to
355-
* complete its operation, we give up our time slice now.
356-
* If we have to retry again, we do sleep a bit.
357-
*/
358-
Sleep(delay[tries]);
359-
tries++;
360-
}
361-
while (ret == -1 && is_file_in_use_error(GetLastError()) &&
362-
ask_yes_no_if_possible("Unlink of file '%s' failed. "
363-
"Should I try again?", pathname))
364-
ret = _wunlink(wpathname);
365-
return ret;
373+
} while (retry_ask_yes_no(&tries, "Unlink of file '%s' failed. "
374+
"Should I try again?", pathname));
375+
return -1;
366376
}
367377

368378
static int is_dir_empty(const wchar_t *wpath)
@@ -389,7 +399,7 @@ static int is_dir_empty(const wchar_t *wpath)
389399

390400
int mingw_rmdir(const char *pathname)
391401
{
392-
int ret, tries = 0;
402+
int tries = 0;
393403
wchar_t wpathname[MAX_LONG_PATH];
394404
struct stat st;
395405

@@ -415,7 +425,11 @@ int mingw_rmdir(const char *pathname)
415425
if (xutftowcs_long_path(wpathname, pathname) < 0)
416426
return -1;
417427

418-
while ((ret = _wrmdir(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
428+
do {
429+
if (!_wrmdir(wpathname)) {
430+
invalidate_lstat_cache();
431+
return 0;
432+
}
419433
if (!is_file_in_use_error(GetLastError()))
420434
errno = err_win_to_posix(GetLastError());
421435
if (errno != EACCES)
@@ -424,23 +438,9 @@ int mingw_rmdir(const char *pathname)
424438
errno = ENOTEMPTY;
425439
break;
426440
}
427-
/*
428-
* We assume that some other process had the source or
429-
* destination file open at the wrong moment and retry.
430-
* In order to give the other process a higher chance to
431-
* complete its operation, we give up our time slice now.
432-
* If we have to retry again, we do sleep a bit.
433-
*/
434-
Sleep(delay[tries]);
435-
tries++;
436-
}
437-
while (ret == -1 && errno == EACCES && is_file_in_use_error(GetLastError()) &&
438-
ask_yes_no_if_possible("Deletion of directory '%s' failed. "
439-
"Should I try again?", pathname))
440-
ret = _wrmdir(wpathname);
441-
if (!ret)
442-
invalidate_lstat_cache();
443-
return ret;
441+
} while (retry_ask_yes_no(&tries, "Deletion of directory '%s' failed. "
442+
"Should I try again?", pathname));
443+
return -1;
444444
}
445445

446446
static inline int needs_hiding(const char *path)
@@ -2650,20 +2650,8 @@ int mingw_rename(const char *pold, const char *pnew)
26502650
SetFileAttributesW(wpnew, attrs);
26512651
}
26522652
}
2653-
if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
2654-
/*
2655-
* We assume that some other process had the source or
2656-
* destination file open at the wrong moment and retry.
2657-
* In order to give the other process a higher chance to
2658-
* complete its operation, we give up our time slice now.
2659-
* If we have to retry again, we do sleep a bit.
2660-
*/
2661-
Sleep(delay[tries]);
2662-
tries++;
2663-
goto repeat;
2664-
}
26652653
if (gle == ERROR_ACCESS_DENIED &&
2666-
ask_yes_no_if_possible("Rename from '%s' to '%s' failed. "
2654+
retry_ask_yes_no(&tries, "Rename from '%s' to '%s' failed. "
26672655
"Should I try again?", pold, pnew))
26682656
goto repeat;
26692657

0 commit comments

Comments
 (0)