diff options
author | Ronnie Sahlberg <sahlberg@google.com> | 2014-11-07 11:38:54 -0800 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2014-11-07 15:45:08 -0800 |
commit | 452ddfa0a59e9d02b717f29d7c537d068d18ebee (patch) | |
tree | 24a28d2d6ecce43b766737393f7abc7405466fb2 | |
parent | b02219f59084bbd18cca5b3b0f7f5b4b621f21a6 (diff) | |
download | git-452ddfa0a59e9d02b717f29d7c537d068d18ebee.tar.gz |
refs.c: add transaction support for renaming a reflog
Add a new transaction function transaction_rename_reflog.
Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r-- | refs.c | 72 | ||||
-rw-r--r-- | refs.h | 8 |
2 files changed, 79 insertions, 1 deletions
@@ -35,6 +35,11 @@ static unsigned char refname_disposition[256] = { * just use the lock taken by the first update. */ #define UPDATE_REFLOG_NOLOCK 0x0200 +/* + * This update is used to replace a new or existing reflog with new content + * held in update->new_reflog. + */ +#define REFLOG_REPLACE 0x0400 /* * Try to read one refname component from the front of refname. @@ -2821,6 +2826,37 @@ static int rename_ref_available(const char *oldname, const char *newname) static int write_ref_sha1(struct ref_lock *lock, const unsigned char *sha1, const char *logmsg); +/* + * This is an optimized function to read the whole reflog as a blob + * into a strbuf. It is used during ref_rename so that we can use an + * efficient method to read the whole log and later write it back to a + * different file. + */ +static int copy_reflog_into_strbuf(const char *refname, struct strbuf *buf) +{ + struct stat st; + int fd; + + if (lstat(git_path("logs/%s", refname), &st) == -1) + return 1; + if ((fd = open(git_path("logs/%s", refname), O_RDONLY)) == -1) { + error("failed to open reflog %s, %s", + refname, strerror(errno)); + return 1; + } + strbuf_init(buf, st.st_size); + strbuf_setlen(buf, st.st_size); + if (read_in_full(fd, buf->buf, st.st_size) != st.st_size) { + close(fd); + error("failed to read reflog %s, %s", + refname, strerror(errno)); + return 1; + } + close(fd); + + return 0; +} + int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg) { unsigned char sha1[20], orig_sha1[20]; @@ -3561,6 +3597,7 @@ struct ref_update { struct lock_file *reflog_lock; char *committer; struct ref_update *orig_update; /* For UPDATE_REFLOG_NOLOCK */ + struct strbuf new_reflog; const char refname[FLEX_ARRAY]; }; @@ -3607,6 +3644,7 @@ void transaction_free(struct transaction *transaction) return; for (i = 0; i < transaction->nr; i++) { + strbuf_release(&transaction->updates[i]->new_reflog); free(transaction->updates[i]->msg); free(transaction->updates[i]->committer); free(transaction->updates[i]); @@ -3622,6 +3660,7 @@ static struct ref_update *add_update(struct transaction *transaction, size_t len = strlen(refname); struct ref_update *update = xcalloc(1, sizeof(*update) + len + 1); + strbuf_init(&update->new_reflog, 0); strcpy((char *)update->refname, refname); update->update_type = update_type; ALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc); @@ -3681,6 +3720,27 @@ int transaction_update_reflog(struct transaction *transaction, return 0; } +int transaction_rename_reflog(struct transaction *transaction, + const char *oldrefname, + const char *newrefname, + struct strbuf *err) +{ + struct ref_update *update; + + if (transaction->state != TRANSACTION_OPEN) + die("BUG: transaction_replace_reflog called for transaction " + "that is not open"); + + update = add_update(transaction, newrefname, UPDATE_LOG); + update->flags = REFLOG_REPLACE; + update->reflog_lock = xcalloc(1, sizeof(struct lock_file)); + if (copy_reflog_into_strbuf(oldrefname, &update->new_reflog)) + die("BUG: failed to read old reflog in " + "transaction_rename_reflog"); + + return 0; +} + int transaction_update_ref(struct transaction *transaction, const char *refname, const unsigned char *new_sha1, @@ -4012,7 +4072,7 @@ int transaction_commit(struct transaction *transaction, continue; if (update->reflog_fd == -1) continue; - if (update->flags & REFLOG_TRUNCATE) + if (update->flags & (REFLOG_TRUNCATE|REFLOG_REPLACE)) if (lseek(update->reflog_fd, 0, SEEK_SET) < 0 || ftruncate(update->reflog_fd, 0)) { error("Could not truncate reflog: %s. %s", @@ -4030,6 +4090,16 @@ int transaction_commit(struct transaction *transaction, rollback_lock_file(update->reflog_lock); update->reflog_fd = -1; } + if (update->flags & REFLOG_REPLACE) + if (write_in_full(update->reflog_fd, + update->new_reflog.buf, + update->new_reflog.len) != + update->new_reflog.len) { + error("Could write to reflog: %s. %s", + update->refname, strerror(errno)); + rollback_lock_file(update->reflog_lock); + update->reflog_fd = -1; + } } /* Commit all reflog files */ @@ -354,6 +354,14 @@ int transaction_update_reflog(struct transaction *transaction, struct strbuf *err); /* + * Rename a reflog. + */ +int transaction_rename_reflog(struct transaction *transaction, + const char *oldrefname, + const char *newrefname, + struct strbuf *err); + +/* * Commit all of the changes that have been queued in transaction, as * atomically as possible. * |