reflog.c: use a reflog transaction when writing during expire

Use a transaction when doing the updates of the reflog during expire_reflog.

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
refs.c: null terminate the string in copy_msg

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
refs.c: track the refnames we are deleting in the transaction structure

Track the names of the refs we are deleting in the ref_transaction structure
instead of building an array of names during _commit.

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
refs.c: update the list of deleted refs during _update instead of _commit

When deleting refs during a transaction, update the list of the refs to be
deleted already during _update instead of waiting until the _commit stage.

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
refs.c: return error instead of dying when locking fails during transaction

Change lock_ref_sha1_basic to return an error instead of dying when
we fail to lock a file during a transaction.

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
refs.c: lock the ref during _update instead of during _commit

Try to lock the ref during the transaction update instead of later during the
commit phase. This allows us to do things such as :

t = transaction_begin()
transaction_update_sha1(t, ref, ...)   /* locking ref */
...
do stuff while we know that ref is locked
...
transaction_commit(t)

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
refs.c: add an error argument to create/delete/update just like commit

Update the signatures for transaction create/delete/update and add
a strbuf err argument we can use to pass an error back to the caller.
We will need this later once we start moving checks from _commit to _update.
Change all callers that would die() on _commit failures to handle _update
failures similarly.

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
refs.c: make _update_reflog take an error argument

Add a strbug argument to the update reflog transaction call so we can return
an error string back to the caller on failure.

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
refs.c: return immediately from _commit if the transaction has an error

If a previous transaction operation has failed and flagged a transaction
as having an error, then return immediately from commit and indicate failure.
Once we move checks from _commit to _update, _update will already have updated
the error string so the caller will know what failed. Thus we don't need to do
anything at all in _commit than return failure.

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
tests: move tests for -z update/delete/verify to after the ref is created

The tests for stdin -z fails for update/delete/verify are of the form
update refs/heads/a $m $m $m
and rely on the fact that when parsed we will first parse everything except
the trailing $m. And once that command has completed it will start parsing
the next commadn, find the trailing $m from before and fail because this
would not look like a proper command. I.e. we do not detect that there are
too many arguments until we have finished the current command and try to parse
the next command.

But since the ref refs/heads/a does not exist at this point in the test, we
actually have two failures that trigger. We have one error that is due to
update refs/heads/a $m $m would be invalid becasue the ref doe snot exist
and we have a second error that is due to the trailing $m causing a "too
many arguments" failure. The current test depends on the order of check for
these two errors which makes the test fragile (and would break the next patch).

Move these tests further down in the test to occur after we have created
refs/heads/a so that there is only one error condition in the test and that
we no longer depend on in which order the checks for error occur.

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
refs.c: check for lock conflicts already in _update

Check for lock conflicts in _update and flag the transaction as errored
instead of waiting until _commit for doing these checks. If there was a lock
failure we check if this was due to a previous update in the same transaction
or not. This so that we can preserve the current error messages on lock failure
and log "Multiple updates for ref '%s' not allowed." when we have multiple
updates in the same transaction and "Cannot lock the ref '%s'." for any other
reason that the lock failed.

This also means that we no longer need to sort all the refs and check for
duplicates during _commit so all that code can be removed too.

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
refs.c allow multiple updates of the same ref in a transaction

Allow multiple updates of a ref in the same transaction as long as
each update has have_old and old_sha1 matches the new_sha1 of the
previous update.

Add a test that verifies that a valid sequence such as
  create ref a
  update ref b a
  update ref c b
works and a test that an invalid sequence such as this still fails:
  update ref a c
  update ref b b
  update ref c c

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
refs.c: release all remaining locks during transaction_free

If there are remaining locks held when we free a transaction, make sure that
we release them instead of relying on the atexit magic to release them for
us. Otherwise, if we perform two transactions on the same ref and the first
transaction is aborted then the second transaction will fail to lock the ref.

This sequence illustrates the bug:

t = transaction_begin()  /* first transaction */
transaction_update_sha1(t, ref, ...)  /* ref is locked */
transaction_free(t)

t = transaction_begin() /* second transaction */
transaction_update_sha1(t, ref, ...) /* will fail since ref was locked above */

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
reflog.c: use the existing transaction to also lock and update the ref

reflog.c has a transaction for updating the reflog. Use this transaction
also for locking the ref itself and updating the ref instead of
lockign the file directly and writing to it. This now completely eliminates
the refs and reflog implementation from reflog.c.

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>