worktree: fix worktree add race

Git runs a stat loop to find a worktree name that's available and then does mkdir on the found name. Turn it to mkdir loop to avoid another invocation of worktree add finding the same free name and creating the directory first. Signed-off-by: Michal Suchanek <msuchanek@suse.de> Acked-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michal Suchanek committed Feb 20, 2019 at 17:16 UTC 7af01f23678dbaeed37773e37737f2ef3db1cb49
1 file changed +7 -5
builtin/worktree.c
+7 -5
@@ -268,10 +268,10 @@ static int add_worktree(const char *path, const char *refname,
268 struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
269 struct strbuf sb = STRBUF_INIT;
270 const char *name;
271 - struct stat st;
271 struct child_process cp = CHILD_PROCESS_INIT;
272 struct argv_array child_env = ARGV_ARRAY_INIT;
274 - int counter = 0, len, ret;
273 + unsigned int counter = 0;
274 + int len, ret;
275 struct strbuf symref = STRBUF_INIT;
276 struct commit *commit = NULL;
277 int is_branch = 0;
@@ -295,8 +295,12 @@ static int add_worktree(const char *path, const char *refname,
295 if (safe_create_leading_directories_const(sb_repo.buf))
296 die_errno(_("could not create leading directories of '%s'"),
297 sb_repo.buf);
298 - while (!stat(sb_repo.buf, &st)) {
298 +
299 + while (mkdir(sb_repo.buf, 0777)) {
300 counter++;
301 + if ((errno != EEXIST) || !counter /* overflow */)
302 + die_errno(_("could not create directory of '%s'"),
303 + sb_repo.buf);
304 strbuf_setlen(&sb_repo, len);
305 strbuf_addf(&sb_repo, "%d", counter);
306 }
@@ -306,8 +310,6 @@ static int add_worktree(const char *path, const char *refname,
310 atexit(remove_junk);
311 sigchain_push_common(remove_junk_on_signal);
312
309 - if (mkdir(sb_repo.buf, 0777))
310 - die_errno(_("could not create directory of '%s'"), sb_repo.buf);
313 junk_git_dir = xstrdup(sb_repo.buf);
314 is_junk = 1;
315