worktree: support creating locked worktrees

When creating a new worktree, we do have a potential race with us
creating the worktree and another process trying to delete the same
worktree as it is being created. As such, the upstream git project has
introduced a flag `git worktree add --locked`, which will cause the
newly created worktree to be locked immediately after its creation. This
mitigates the race condition.

We want to be able to mirror the same behavior. As such, a new flag
`locked` is added to the options structure of `git_worktree_add` which
allows the user to enable this behavior.
diff --git a/include/git2/worktree.h b/include/git2/worktree.h
index bc1e402..84e2bc9 100644
--- a/include/git2/worktree.h
+++ b/include/git2/worktree.h
@@ -76,10 +76,12 @@
 
 typedef struct git_worktree_add_options {
 	unsigned int version;
+
+	char lock; /**< lock newly created worktree */
 } git_worktree_add_options;
 
 #define GIT_WORKTREE_ADD_OPTIONS_VERSION 1
-#define GIT_WORKTREE_ADD_OPTIONS_INIT {GIT_WORKTREE_ADD_OPTIONS_VERSION}
+#define GIT_WORKTREE_ADD_OPTIONS_INIT {GIT_WORKTREE_ADD_OPTIONS_VERSION,0}
 
 /**
  * Initializes a `git_worktree_add_options` with default vaules.
diff --git a/src/worktree.c b/src/worktree.c
index 6e797f3..b9ed759 100644
--- a/src/worktree.c
+++ b/src/worktree.c
@@ -318,6 +318,21 @@
 	if ((err = git_path_prettify_dir(&wddir, worktree, NULL)) < 0)
 		goto out;
 
+	if (wtopts.lock) {
+		int fd;
+
+		if ((err = git_buf_joinpath(&buf, gitdir.ptr, "locked")) < 0)
+			goto out;
+
+		if ((fd = p_creat(buf.ptr, 0644)) < 0) {
+			err = fd;
+			goto out;
+		}
+
+		p_close(fd);
+		git_buf_clear(&buf);
+	}
+
 	/* Create worktree .git file */
 	if ((err = git_buf_printf(&buf, "gitdir: %s\n", gitdir.ptr)) < 0)
 		goto out;
diff --git a/tests/worktree/worktree.c b/tests/worktree/worktree.c
index f908958..7ab86cc 100644
--- a/tests/worktree/worktree.c
+++ b/tests/worktree/worktree.c
@@ -228,6 +228,31 @@
 	git_repository_free(repo);
 }
 
+void test_worktree_worktree__add_locked(void)
+{
+	git_worktree *wt;
+	git_repository *repo;
+	git_reference *branch;
+	git_buf path = GIT_BUF_INIT;
+	git_worktree_add_options opts = GIT_WORKTREE_ADD_OPTIONS_INIT;
+
+	opts.lock = 1;
+
+	cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-locked"));
+	cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-locked", path.ptr, &opts));
+
+	/* Open and verify created repo */
+	cl_assert(git_worktree_is_locked(NULL, wt));
+	cl_git_pass(git_repository_open(&repo, path.ptr));
+	cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-locked/") == 0);
+	cl_git_pass(git_branch_lookup(&branch, repo, "worktree-locked", GIT_BRANCH_LOCAL));
+
+	git_buf_free(&path);
+	git_worktree_free(wt);
+	git_reference_free(branch);
+	git_repository_free(repo);
+}
+
 void test_worktree_worktree__init_existing_branch(void)
 {
 	git_reference *head, *branch;