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

[PATCH 4/5] safe_create_leading_directories(): fix a mkdir/rmdir race

From
Michael Haggerty <mhagger@alum.mit.edu>
Date
Dec 22, 2013, 07:14 UTC
Message-ID
<1387696451-32224-5-git-send-email-mhagger@alum.mit.edu>
In-Reply-To
<1387696451-32224-1-git-send-email-mhagger@alum.mit.edu>

It could be that some other process is trying to clean up empty directories at the same time that safe_create_leading_directories() is attempting to create them. In this case, it could happen that directory "a/b" was present at the end of one iteration of the loop (either it was already present or we just created it ourselves), but by the time we try to create directory "a/b/c", directory "a/b" has been deleted. In fact, directory "a" might also have been deleted.

So, if a call to mkdir() fails with ENOENT, then try checking/making all directories again from the beginning. Attempt up to three times before giving up.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
 sha1_file.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
diff --git a/sha1_file.c b/sha1_file.c
index dcfd35a..abcb56b 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -108,6 +108,7 @@ int mkdir_in_gitdir(const char *path)
 int safe_create_leading_directories(char *path)
 {
 	char *next_component = path + offset_1st_component(path);
+	int attempts = 3;
 	int retval = 0;
 
 	while (!retval && next_component) {
@@ -132,6 +133,16 @@ int safe_create_leading_directories(char *path)
 			if (errno == EEXIST &&
 			    !stat(path, &st) && S_ISDIR(st.st_mode)) {
 				; /* somebody created it since we checked */
+			} else if (errno == ENOENT && --attempts) {
+				/*
+				 * Either mkdir() failed bacause
+				 * somebody just pruned the containing
+				 * directory, or stat() failed because
+				 * the file that was in our way was
+				 * just removed.  Either way, try
+				 * again from the beginning:
+				 */
+				next_component = path + offset_1st_component(path);
 			} else {
 				retval = -1;
 			}
-- 
1.8.5.1
Previous: Michael HaggertyNext: Ramsay Jones
Message 10 of 15 in “Fix two mkdir/rmdir races”
  1. 0/5 Fix two mkdir/rmdir racesMichael Haggerty, Dec 22, 2013
  2. 1/5 safe_create_leading_directories(): modernize format of "if" chainingMichael Haggerty, Dec 22, 2013
  3. Jonathan NiederDec 26, 2013
  4. 2/5 safe_create_leading_directories(): reduce scope of local variableMichael Haggerty, Dec 22, 2013
  5. Jonathan NiederDec 26, 2013
  6. Michael HaggertyJan 1, 2014
  7. 3/5 safe_create_leading_directories(): add "slash" pointerMichael Haggerty, Dec 22, 2013
  8. Jonathan NiederDec 26, 2013
  9. Michael HaggertyJan 1, 2014
  10. 4/5 safe_create_leading_directories(): fix a mkdir/rmdir raceMichael Haggerty, Dec 22, 2013
  11. Ramsay JonesDec 22, 2013
  12. Jonathan NiederDec 26, 2013
  13. Michael HaggertyJan 2, 2014
  14. 5/5 rename_ref(): fix a mkdir()/rmdir() raceMichael Haggerty, Dec 22, 2013
  15. Jonathan NiederDec 26, 2013

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.