[PATCH 07/15] refs.c: add a transaction function to append a reflog entry
commit de045215a52a6a9591b0e786488de2293d79d245 upstream. Define a new transaction update type, UPDATE_LOG, and a new function transaction_update_reflog. This function will lock the reflog and append an entry to it during transaction commit. Change-Id: I8cc935ef311688d561d447fa51b44ac98492693b Signed-off-by: Ronnie Sahlberg sahlb...@google.com Signed-off-by: Jonathan Nieder jrnie...@gmail.com --- refs.c | 102 +++-- refs.h | 12 2 files changed, 112 insertions(+), 2 deletions(-) diff --git a/refs.c b/refs.c index 0e11b1c..100b3a3 100644 --- a/refs.c +++ b/refs.c @@ -3517,7 +3517,8 @@ int for_each_reflog(each_ref_fn fn, void *cb_data) } enum transaction_update_type { - UPDATE_SHA1 = 0 + UPDATE_SHA1 = 0, + UPDATE_LOG = 1 }; /** @@ -3535,6 +3536,12 @@ struct ref_update { struct ref_lock *lock; int type; char *msg; + + /* used by reflog updates */ + int reflog_fd; + struct lock_file reflog_lock; + char *committer; + const char refname[FLEX_ARRAY]; }; @@ -3581,6 +3588,7 @@ void transaction_free(struct transaction *transaction) for (i = 0; i transaction-nr; i++) { free(transaction-updates[i]-msg); + free(transaction-updates[i]-committer); free(transaction-updates[i]); } free(transaction-updates); @@ -3601,6 +3609,41 @@ static struct ref_update *add_update(struct transaction *transaction, return update; } +int transaction_update_reflog(struct transaction *transaction, + const char *refname, + const unsigned char *new_sha1, + const unsigned char *old_sha1, + const unsigned char *email, + unsigned long timestamp, int tz, + const char *msg, int flags, + struct strbuf *err) +{ + struct ref_update *update; + + if (transaction-state != TRANSACTION_OPEN) + die(BUG: update_reflog called for transaction that is not open); + + update = add_update(transaction, refname, UPDATE_LOG); + hashcpy(update-new_sha1, new_sha1); + hashcpy(update-old_sha1, old_sha1); + update-reflog_fd = -1; + if (email) { + struct strbuf buf = STRBUF_INIT; + char sign = (tz 0) ? '-' : '+'; + int zone = (tz 0) ? (-tz) : tz; + + strbuf_addf(buf, %s %lu %c%04d, email, timestamp, sign, + zone); + update-committer = xstrdup(buf.buf); + strbuf_release(buf); + } + if (msg) + update-msg = xstrdup(msg); + update-flags = flags; + + return 0; +} + int transaction_update_ref(struct transaction *transaction, const char *refname, const unsigned char *new_sha1, @@ -3773,7 +3816,28 @@ int transaction_commit(struct transaction *transaction, } } - /* Perform updates first so live commits remain referenced */ + /* Lock all reflog files */ + for (i = 0; i n; i++) { + struct ref_update *update = updates[i]; + + if (update-update_type != UPDATE_LOG) + continue; + update-reflog_fd = hold_lock_file_for_append( + update-reflog_lock, + git_path(logs/%s, update-refname), + 0); + if (update-reflog_fd 0) { + const char *str = Cannot lock reflog for '%s'. %s; + + ret = -1; + if (err) + strbuf_addf(err, str, update-refname, + strerror(errno)); + goto cleanup; + } + } + + /* Perform ref updates first so live commits remain referenced */ for (i = 0; i n; i++) { struct ref_update *update = updates[i]; @@ -3809,6 +3873,40 @@ int transaction_commit(struct transaction *transaction, } } + /* Update all reflog files */ + for (i = 0; i n; i++) { + struct ref_update *update = updates[i]; + + if (update-update_type != UPDATE_LOG) + continue; + if (update-reflog_fd == -1) + continue; + + if (log_ref_write_fd(update-reflog_fd, update-old_sha1, +update-new_sha1, +update-committer, update-msg)) { + error(Could write to reflog: %s. %s, + update-refname, strerror(errno)); +
[PATCH 07/15] refs.c: add a transaction function to append a reflog entry
Define a new transaction update type, UPDATE_LOG, and a new function transaction_update_reflog. This function will lock the reflog and append an entry to it during transaction commit. Signed-off-by: Ronnie Sahlberg sahlb...@google.com --- refs.c | 103 +++-- refs.h | 12 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/refs.c b/refs.c index a479ddd..b010d6d 100644 --- a/refs.c +++ b/refs.c @@ -3385,7 +3385,8 @@ int for_each_reflog(each_ref_fn fn, void *cb_data) } enum transaction_update_type { - UPDATE_SHA1 = 0 + UPDATE_SHA1 = 0, + UPDATE_LOG = 1 }; /** @@ -3403,6 +3404,12 @@ struct ref_update { struct ref_lock *lock; int type; char *msg; + + /* used by reflog updates */ + int reflog_fd; + struct lock_file reflog_lock; + char *committer; + const char refname[FLEX_ARRAY]; }; @@ -3451,6 +3458,7 @@ void transaction_free(struct ref_transaction *transaction) for (i = 0; i transaction-nr; i++) { free(transaction-updates[i]-msg); + free(transaction-updates[i]-committer); free(transaction-updates[i]); } free(transaction-updates); @@ -3471,6 +3479,42 @@ static struct ref_update *add_update(struct ref_transaction *transaction, return update; } +int transaction_update_reflog(struct ref_transaction *transaction, + const char *refname, + const unsigned char *new_sha1, + const unsigned char *old_sha1, + const unsigned char *email, + unsigned long timestamp, int tz, + const char *msg, int flags, + struct strbuf *err) +{ + struct ref_update *update; + + if (transaction-state != REF_TRANSACTION_OPEN) + die(BUG: update_reflog called for transaction that is not + open); + + update = add_update(transaction, refname, UPDATE_LOG); + hashcpy(update-new_sha1, new_sha1); + hashcpy(update-old_sha1, old_sha1); + update-reflog_fd = -1; + if (email) { + struct strbuf buf = STRBUF_INIT; + char sign = (tz 0) ? '-' : '+'; + int zone = (tz 0) ? (-tz) : tz; + + strbuf_addf(buf, %s %lu %c%04d, email, timestamp, sign, + zone); + update-committer = xstrdup(buf.buf); + strbuf_release(buf); + } + if (msg) + update-msg = xstrdup(msg); + update-flags = flags; + + return 0; +} + int transaction_update_sha1(struct ref_transaction *transaction, const char *refname, const unsigned char *new_sha1, @@ -3646,7 +3690,28 @@ int transaction_commit(struct ref_transaction *transaction, } } - /* Perform updates first so live commits remain referenced */ + /* Lock all reflog files */ + for (i = 0; i n; i++) { + struct ref_update *update = updates[i]; + + if (update-update_type != UPDATE_LOG) + continue; + update-reflog_fd = hold_lock_file_for_append( + update-reflog_lock, + git_path(logs/%s, update-refname), + 0); + if (update-reflog_fd 0) { + const char *str = Cannot lock reflog for '%s'. %s; + + ret = -1; + if (err) + strbuf_addf(err, str, update-refname, + strerror(errno)); + goto cleanup; + } + } + + /* Perform ref updates first so live commits remain referenced */ for (i = 0; i n; i++) { struct ref_update *update = updates[i]; @@ -3682,6 +3747,40 @@ int transaction_commit(struct ref_transaction *transaction, } } + /* Update all reflog files */ + for (i = 0; i n; i++) { + struct ref_update *update = updates[i]; + + if (update-update_type != UPDATE_LOG) + continue; + if (update-reflog_fd == -1) + continue; + + if (log_ref_write_fd(update-reflog_fd, update-old_sha1, +update-new_sha1, +update-committer, update-msg)) { + error(Could write to reflog: %s. %s, + update-refname, strerror(errno)); + rollback_lock_file(update-reflog_lock); + update-reflog_fd = -1; + } + } + +