git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 3/4] mingw: make failures to unlink or move raise a question

From
Heiko Voigt <hvoigt@hvoigt.net>
Date
Nov 7, 2010, 14:56 UTC
Message-ID
<b25a0668848fd85521da9b7dd7e1ca82c2c16e7f.1289139299.git.hvoigt@hvoigt.net>
In-Reply-To
<cover.1289139299.git.hvoigt@hvoigt.net>

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 <hvoigt@hvoigt.net>
---
 compat/mingw.c |   82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 82 insertions(+), 0 deletions(-)
diff --git a/compat/mingw.c b/compat/mingw.c
index bf9ffb8..b66bf89 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,6 +3,7 @@
 #include <conio.h>
 #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 };
@@ -163,6 +164,78 @@ int mingw_mkdir(const char *path, int mode)
 	return ret;
 }
 
+static int read_yes_no_answer()
+{
+	char answer[1024];
+
+	if (fgets(answer, sizeof(answer), stdin)) {
+		size_t answer_len = strlen(answer);
+		int got_full_line = 0, c;
+
+		/* remove the newline */
+		if (answer_len >= 2 && answer[answer_len-2] == '\r') {
+			answer[answer_len-2] = '\0';
+			got_full_line = 1;
+		}
+		else if (answer_len >= 1 && answer[answer_len-1] == '\n') {
+			answer[answer_len-1] = '\0';
+			got_full_line = 1;
+		}
+		/* flush the buffer in case we did not get the full line */
+		if (!got_full_line)
+			while((c = getchar()) != EOF && c != '\n');
+	} else
+		/* we could not read, return the
+		 * default answer which is no */
+		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;
+
+	/* did not find an answer we understand */
+	return -1;
+}
+
+static int ask_user_yes_no(const char *format, ...)
+{
+	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) {
+		int answer;
+		va_start(args, format);
+		vfprintf(stderr, format, args);
+		va_end(args);
+		fprintf(stderr, " (y/n)? ");
+
+		if ((answer = read_yes_no_answer()) >= 0)
+			return answer;
+
+		fprintf(stderr, "Sorry, I did not understand your answer. "
+				"Please type 'y' or 'n'\n");
+	}
+}
+
 #undef unlink
 int mingw_unlink(const char *pathname)
 {
@@ -183,6 +256,10 @@ int mingw_unlink(const char *pathname)
 		Sleep(delay[tries]);
 		tries++;
 	}
+	while (ret == -1 && is_file_in_use_error() &&
+	       ask_user_yes_no("Unlink of file '%s' failed. "
+			"Should I try again?", pathname))
+	       ret = unlink(pathname);
 	return ret;
 }
 
@@ -1343,6 +1420,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;
 }
-- 
1.7.2.2.177.geec0d
Previous: Heiko VoigtNext: Heiko Voigt
Message 31 of 38 in “Pull request for msysGit patches”
  1. Pat ThoytsSep 28, 2010
  2. Junio C HamanoSep 28, 2010
  3. Johannes SixtSep 28, 2010
  4. Junio C HamanoSep 29, 2010
  5. Ævar Arnfjörð BjarmasonSep 28, 2010
  6. Pat ThoytsSep 30, 2010
  7. Ævar Arnfjörð BjarmasonSep 30, 2010
  8. Erik Faye-LundSep 30, 2010
  9. Eric SunshineSep 29, 2010
  10. msysGit patches for upstreamPat Thoyts, Sep 29, 2010
  11. Junio C HamanoSep 29, 2010
  12. 1/2 Make sure that git_getpass() never returns NULLPat Thoyts, Sep 29, 2010
  13. 2/2 Fix typo in pack-objects' usagePat Thoyts, Sep 29, 2010
  14. Johannes SixtSep 28, 2010
  15. Erik Faye-LundSep 28, 2010
  16. Johannes SixtSep 28, 2010
  17. Erik Faye-LundSep 28, 2010
  18. Erik Faye-LundSep 28, 2010
  19. Jonathan NiederSep 28, 2010
  20. Junio C HamanoSep 29, 2010
  21. Pat ThoytsSep 29, 2010
  22. Eric SunshineSep 29, 2010
  23. Junio C HamanoSep 29, 2010
  24. Eric SunshineSep 29, 2010
  25. git-am: fix detection of absolute paths for windowsPat Thoyts, Sep 30, 2010
  26. Johannes SixtOct 1, 2010
  27. git-am: fix detection of absolute paths for windowsPat Thoyts, Sep 30, 2010
  28. 0/4 make open/unlink failures user friendly on windows using retry/abortHeiko Voigt, Nov 7, 2010
  29. 1/4 mingw: move unlink wrapper to mingw.cHeiko Voigt, Nov 7, 2010
  30. 2/4 mingw: work around irregular failures of unlink on windowsHeiko Voigt, Nov 7, 2010
  31. 3/4 mingw: make failures to unlink or move raise a questionHeiko Voigt, Nov 7, 2010
  32. 4/4 mingw: add fallback for rmdir in case directory is in useHeiko Voigt, Nov 7, 2010
  33. Johannes SixtNov 7, 2010
  34. Heiko VoigtNov 7, 2010
  35. Johannes SixtNov 7, 2010
  36. yj2133011Sep 29, 2010
  37. Ramsay JonesSep 29, 2010
  38. Eric SunshineSep 29, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.