[PATCH v4 16/17] sparse-checkout: write using lockfile
From: Derrick Stolee via GitGitGadget <hidden>
Date: 2019-10-15 13:56:28
Subsystem:
the rest · Maintainer:
Linus Torvalds
From: Derrick Stolee <redacted> If two 'git sparse-checkout set' subcommands are launched at the same time, the behavior can be unexpected as they compete to write the sparse-checkout file and update the working directory. Take a lockfile around the writes to the sparse-checkout file. In addition, acquire this lock around the working directory update to avoid two commands updating the working directory in different ways. Signed-off-by: Derrick Stolee <redacted> --- builtin/sparse-checkout.c | 15 ++++++++++++--- t/t1091-sparse-checkout-builtin.sh | 7 +++++++ 2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 595955d4fc..b319966a79 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c@@ -305,6 +305,8 @@ static int write_patterns_and_update(struct pattern_list *pl) { char *sparse_filename; FILE *fp; + int fd; + struct lock_file lk = LOCK_INIT; int result; if (!core_apply_sparse_checkout) {
@@ -314,21 +316,28 @@ static int write_patterns_and_update(struct pattern_list *pl) result = update_working_directory(pl); + sparse_filename = get_sparse_checkout_filename(); + fd = hold_lock_file_for_update(&lk, sparse_filename, + LOCK_DIE_ON_ERROR); + + result = update_working_directory(pl); if (result) { + rollback_lock_file(&lk); + free(sparse_filename); clear_pattern_list(pl); update_working_directory(NULL); return result; } - sparse_filename = get_sparse_checkout_filename(); - fp = fopen(sparse_filename, "w"); + fp = fdopen(fd, "w"); if (core_sparse_checkout_cone) write_cone_to_file(fp, pl); else write_patterns_to_file(fp, pl); - fclose(fp); + fflush(fp); + commit_lock_file(&lk); free(sparse_filename); clear_pattern_list(pl);
diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh
index ecb5a63671..48493e1012 100755
--- a/t/t1091-sparse-checkout-builtin.sh
+++ b/t/t1091-sparse-checkout-builtin.sh@@ -262,4 +262,11 @@ test_expect_success 'revert to old sparse-checkout on bad update' ' test_cmp dir expect ' +test_expect_success 'fail when lock is taken' ' + test_when_finished rm -rf repo/.git/info/sparse-checkout.lock && + touch repo/.git/info/sparse-checkout.lock && + test_must_fail git -C repo sparse-checkout set deep 2>err && + test_i18ngrep "File exists" err +' + test_done
--
gitgitgadget