We don't actually need the locking functionality, because we already hold the lock on the reference itself, which is how the reflog file is locked. But the lock_file code still does some of the bookkeeping for us and is more careful than the old code here was. For example: * Correctly handle the case that the reflog lock file already exists for some reason or cannot be opened. * Correctly clean up the lockfile if the program dies. Signed-off-by: Michael Haggerty <mhagger@xxxxxxxxxxxx> --- builtin/reflog.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/builtin/reflog.c b/builtin/reflog.c index a282e60..d344d45 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -349,12 +349,14 @@ static int push_tip_to_list(const char *refname, const unsigned char *sha1, int return 0; } +static struct lock_file reflog_lock; + static int expire_reflog(const char *refname, const unsigned char *sha1, void *cb_data) { struct cmd_reflog_expire_cb *cmd = cb_data; struct expire_reflog_cb cb; struct ref_lock *lock; - char *log_file, *newlog_path = NULL; + char *log_file; struct commit *tip_commit; struct commit_list *tips; int status = 0; @@ -372,10 +374,14 @@ static int expire_reflog(const char *refname, const unsigned char *sha1, void *c unlock_ref(lock); return 0; } + log_file = git_pathdup("logs/%s", refname); if (!cmd->dry_run) { - newlog_path = git_pathdup("logs/%s.lock", refname); - cb.newlog = fopen(newlog_path, "w"); + if (hold_lock_file_for_update(&reflog_lock, log_file, 0) < 0) + goto failure; + cb.newlog = fdopen_lock_file(&reflog_lock, "w"); + if (!cb.newlog) + goto failure; } cb.cmd = cmd; @@ -423,10 +429,9 @@ static int expire_reflog(const char *refname, const unsigned char *sha1, void *c } if (cb.newlog) { - if (fclose(cb.newlog)) { - status |= error("%s: %s", strerror(errno), - newlog_path); - unlink(newlog_path); + if (close_lock_file(&reflog_lock)) { + status |= error("Couldn't write %s: %s", log_file, + strerror(errno)); } else if (cmd->updateref && (write_in_full(lock->lock_fd, sha1_to_hex(cb.last_kept_sha1), 40) != 40 || @@ -434,21 +439,23 @@ static int expire_reflog(const char *refname, const unsigned char *sha1, void *c close_ref(lock) < 0)) { status |= error("Couldn't write %s", lock->lk->filename.buf); - unlink(newlog_path); - } else if (rename(newlog_path, log_file)) { - status |= error("cannot rename %s to %s", - newlog_path, log_file); - unlink(newlog_path); + rollback_lock_file(&reflog_lock); + } else if (commit_lock_file(&reflog_lock)) { + status |= error("cannot rename %s.lock to %s", + log_file, log_file); } else if (cmd->updateref && commit_ref(lock)) { status |= error("Couldn't set %s", lock->ref_name); - } else { - adjust_shared_perm(log_file); } } - free(newlog_path); free(log_file); unlock_ref(lock); return status; + + failure: + rollback_lock_file(&reflog_lock); + free(log_file); + unlock_ref(lock); + return -1; } static int collect_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data) -- 2.1.3 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html