@ -352,9 +352,10 @@ static int push_tip_to_list(const char *refname, const unsigned char *sha1, int
@@ -352,9 +352,10 @@ static int push_tip_to_list(const char *refname, const unsigned char *sha1, int
static int expire_reflog(const char *refname, const unsigned char *sha1,
struct cmd_reflog_expire_cb *cmd)
{
static struct lock_file reflog_lock;
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;
@ -362,8 +363,9 @@ static int expire_reflog(const char *refname, const unsigned char *sha1,
@@ -362,8 +363,9 @@ static int expire_reflog(const char *refname, const unsigned char *sha1,
memset(&cb, 0, sizeof(cb));
/*
* we take the lock for the ref itself to prevent it from
* getting updated.
* The reflog file is locked by holding the lock on the
* reference itself, plus we might need to update the
* reference if --updateref was specified:
*/
lock = lock_any_ref_for_update(refname, sha1, 0, NULL);
if (!lock)
@ -372,10 +374,29 @@ static int expire_reflog(const char *refname, const unsigned char *sha1,
@@ -372,10 +374,29 @@ static int expire_reflog(const char *refname, const unsigned char *sha1,
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");
/*
* Even though holding $GIT_DIR/logs/$reflog.lock has
* no locking implications, we use the lock_file
* machinery here anyway because it does a lot of the
* work we need, including cleaning up if the program
* exits unexpectedly.
*/
if (hold_lock_file_for_update(&reflog_lock, log_file, 0) < 0) {
struct strbuf err = STRBUF_INIT;
unable_to_lock_message(log_file, errno, &err);
error("%s", err.buf);
strbuf_release(&err);
goto failure;
}
cb.newlog = fdopen_lock_file(&reflog_lock, "w");
if (!cb.newlog) {
error("cannot fdopen %s (%s)",
reflog_lock.filename.buf, strerror(errno));
goto failure;
}
}
cb.cmd = cmd;
@ -423,32 +444,33 @@ static int expire_reflog(const char *refname, const unsigned char *sha1,
@@ -423,32 +444,33 @@ static int expire_reflog(const char *refname, const unsigned char *sha1,
}
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 ||
write_str_in_full(lock->lock_fd, "\n") != 1 ||
close_ref(lock) < 0)) {
status |= error("Couldn't write %s",
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("unable to commit reflog '%s' (%s)",
log_file, strerror(errno));
} else if (cmd->updateref && commit_ref(lock)) {
status |= error("Couldn't set %s", lock->ref_name);
} else {
adjust_shared_perm(log_file);
status |= error("couldn't set %s", lock->ref_name);
}
}
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)