Skip to content

Commit cc2f2bf

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 b1896b2 commit cc2f2bf

File tree

1 file changed

+43
-54
lines changed

1 file changed

+43
-54
lines changed

compat/mingw.c

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

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

11-
static const int delay[] = { 0, 1, 10, 20, 40 };
1211
unsigned int _CRT_fmode = _O_BINARY;
1312

1413
int err_win_to_posix(DWORD winerr)
@@ -173,15 +172,12 @@ static int read_yes_no_answer(void)
173172
return -1;
174173
}
175174

176-
static int ask_yes_no_if_possible(const char *format, ...)
175+
static int ask_yes_no_if_possible(const char *format, va_list args)
177176
{
178177
char question[4096];
179178
const char *retry_hook[] = { NULL, NULL, NULL };
180-
va_list args;
181179

182-
va_start(args, format);
183180
vsnprintf(question, sizeof(question), format, args);
184-
va_end(args);
185181

186182
if ((retry_hook[0] = mingw_getenv("GIT_ASK_YESNO"))) {
187183
retry_hook[1] = question;
@@ -203,33 +199,48 @@ static int ask_yes_no_if_possible(const char *format, ...)
203199
}
204200
}
205201

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

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

235246
static int is_dir_empty(const wchar_t *wpath)
@@ -256,12 +267,14 @@ static int is_dir_empty(const wchar_t *wpath)
256267

257268
int mingw_rmdir(const char *pathname)
258269
{
259-
int ret, tries = 0;
270+
int tries = 0;
260271
wchar_t wpathname[MAX_LONG_PATH];
261272
if (xutftowcs_long_path(wpathname, pathname) < 0)
262273
return -1;
263274

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

290291
static int make_hidden(const wchar_t *path)
@@ -1783,20 +1784,8 @@ int mingw_rename(const char *pold, const char *pnew)
17831784
SetFileAttributesW(wpnew, attrs);
17841785
}
17851786
}
1786-
if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
1787-
/*
1788-
* We assume that some other process had the source or
1789-
* destination file open at the wrong moment and retry.
1790-
* In order to give the other process a higher chance to
1791-
* complete its operation, we give up our time slice now.
1792-
* If we have to retry again, we do sleep a bit.
1793-
*/
1794-
Sleep(delay[tries]);
1795-
tries++;
1796-
goto repeat;
1797-
}
17981787
if (gle == ERROR_ACCESS_DENIED &&
1799-
ask_yes_no_if_possible("Rename from '%s' to '%s' failed. "
1788+
retry_ask_yes_no(&tries, "Rename from '%s' to '%s' failed. "
18001789
"Should I try again?", pold, pnew))
18011790
goto repeat;
18021791

0 commit comments

Comments
 (0)