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