From 9229029bb52cbed0b0e18922e0603e150c82c170 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 14be1bbb2e..d813203ea0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1305,6 +1358,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } -- 2.11.4.GIT