Merge branch 'rs/ref-transaction-0'
Early part of the "ref transaction" topic. * rs/ref-transaction-0: refs.c: change ref_transaction_update() to do error checking and return status refs.c: remove the onerr argument to ref_transaction_commit update-ref: use err argument to get error from ref_transaction_commit refs.c: make update_ref_write update a strbuf on failure refs.c: make ref_update_reject_duplicates take a strbuf argument for errors refs.c: log_ref_write should try to return meaningful errno refs.c: make resolve_ref_unsafe set errno to something meaningful on error refs.c: commit_packed_refs to return a meaningful errno on failure refs.c: make remove_empty_directories always set errno to something sane refs.c: verify_lock should set errno to something meaningful refs.c: make sure log_ref_setup returns a meaningful errno refs.c: add an err argument to repack_without_refs lockfile.c: make lock_file return a meaningful errno on failurei lockfile.c: add a new public function unable_to_lock_message refs.c: add a strbuf argument to ref_transaction_commit for error logging refs.c: allow passing NULL to ref_transaction_free refs.c: constify the sha arguments for ref_transaction_create|delete|update refs.c: ref_transaction_commit should not free the transaction refs.c: remove ref_transaction_rollback
This commit is contained in:
commit
19a249ba83
@ -754,7 +754,7 @@ static int remove_branches(struct string_list *branches)
|
|||||||
branch_names = xmalloc(branches->nr * sizeof(*branch_names));
|
branch_names = xmalloc(branches->nr * sizeof(*branch_names));
|
||||||
for (i = 0; i < branches->nr; i++)
|
for (i = 0; i < branches->nr; i++)
|
||||||
branch_names[i] = branches->items[i].string;
|
branch_names[i] = branches->items[i].string;
|
||||||
result |= repack_without_refs(branch_names, branches->nr);
|
result |= repack_without_refs(branch_names, branches->nr, NULL);
|
||||||
free(branch_names);
|
free(branch_names);
|
||||||
|
|
||||||
for (i = 0; i < branches->nr; i++) {
|
for (i = 0; i < branches->nr; i++) {
|
||||||
@ -1332,7 +1332,8 @@ static int prune_remote(const char *remote, int dry_run)
|
|||||||
for (i = 0; i < states.stale.nr; i++)
|
for (i = 0; i < states.stale.nr; i++)
|
||||||
delete_refs[i] = states.stale.items[i].util;
|
delete_refs[i] = states.stale.items[i].util;
|
||||||
if (!dry_run)
|
if (!dry_run)
|
||||||
result |= repack_without_refs(delete_refs, states.stale.nr);
|
result |= repack_without_refs(delete_refs,
|
||||||
|
states.stale.nr, NULL);
|
||||||
free(delete_refs);
|
free(delete_refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ static struct ref_transaction *transaction;
|
|||||||
|
|
||||||
static char line_termination = '\n';
|
static char line_termination = '\n';
|
||||||
static int update_flags;
|
static int update_flags;
|
||||||
|
static struct strbuf err = STRBUF_INIT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse one whitespace- or NUL-terminated, possibly C-quoted argument
|
* Parse one whitespace- or NUL-terminated, possibly C-quoted argument
|
||||||
@ -197,8 +198,9 @@ static const char *parse_cmd_update(struct strbuf *input, const char *next)
|
|||||||
if (*next != line_termination)
|
if (*next != line_termination)
|
||||||
die("update %s: extra input: %s", refname, next);
|
die("update %s: extra input: %s", refname, next);
|
||||||
|
|
||||||
ref_transaction_update(transaction, refname, new_sha1, old_sha1,
|
if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
|
||||||
update_flags, have_old);
|
update_flags, have_old, &err))
|
||||||
|
die("%s", err.buf);
|
||||||
|
|
||||||
update_flags = 0;
|
update_flags = 0;
|
||||||
free(refname);
|
free(refname);
|
||||||
@ -286,8 +288,9 @@ static const char *parse_cmd_verify(struct strbuf *input, const char *next)
|
|||||||
if (*next != line_termination)
|
if (*next != line_termination)
|
||||||
die("verify %s: extra input: %s", refname, next);
|
die("verify %s: extra input: %s", refname, next);
|
||||||
|
|
||||||
ref_transaction_update(transaction, refname, new_sha1, old_sha1,
|
if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
|
||||||
update_flags, have_old);
|
update_flags, have_old, &err))
|
||||||
|
die("%s", err.buf);
|
||||||
|
|
||||||
update_flags = 0;
|
update_flags = 0;
|
||||||
free(refname);
|
free(refname);
|
||||||
@ -359,17 +362,16 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
|||||||
die("Refusing to perform update with empty message.");
|
die("Refusing to perform update with empty message.");
|
||||||
|
|
||||||
if (read_stdin) {
|
if (read_stdin) {
|
||||||
int ret;
|
|
||||||
transaction = ref_transaction_begin();
|
transaction = ref_transaction_begin();
|
||||||
|
|
||||||
if (delete || no_deref || argc > 0)
|
if (delete || no_deref || argc > 0)
|
||||||
usage_with_options(git_update_ref_usage, options);
|
usage_with_options(git_update_ref_usage, options);
|
||||||
if (end_null)
|
if (end_null)
|
||||||
line_termination = '\0';
|
line_termination = '\0';
|
||||||
update_refs_stdin();
|
update_refs_stdin();
|
||||||
ret = ref_transaction_commit(transaction, msg,
|
if (ref_transaction_commit(transaction, msg, &err))
|
||||||
UPDATE_REFS_DIE_ON_ERR);
|
die("%s", err.buf);
|
||||||
return ret;
|
ref_transaction_free(transaction);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end_null)
|
if (end_null)
|
||||||
|
4
cache.h
4
cache.h
@ -578,6 +578,8 @@ struct lock_file {
|
|||||||
#define LOCK_DIE_ON_ERROR 1
|
#define LOCK_DIE_ON_ERROR 1
|
||||||
#define LOCK_NODEREF 2
|
#define LOCK_NODEREF 2
|
||||||
extern int unable_to_lock_error(const char *path, int err);
|
extern int unable_to_lock_error(const char *path, int err);
|
||||||
|
extern void unable_to_lock_message(const char *path, int err,
|
||||||
|
struct strbuf *buf);
|
||||||
extern NORETURN void unable_to_lock_index_die(const char *path, int err);
|
extern NORETURN void unable_to_lock_index_die(const char *path, int err);
|
||||||
extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
|
extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
|
||||||
extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
|
extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
|
||||||
@ -995,7 +997,7 @@ extern int read_ref(const char *refname, unsigned char *sha1);
|
|||||||
* NULL. If more than MAXDEPTH recursive symbolic lookups are needed,
|
* NULL. If more than MAXDEPTH recursive symbolic lookups are needed,
|
||||||
* give up and return NULL.
|
* give up and return NULL.
|
||||||
*
|
*
|
||||||
* errno is sometimes set on errors, but not always.
|
* errno is set to something meaningful on error.
|
||||||
*/
|
*/
|
||||||
extern const char *resolve_ref_unsafe(const char *ref, unsigned char *sha1, int reading, int *flag);
|
extern const char *resolve_ref_unsafe(const char *ref, unsigned char *sha1, int reading, int *flag);
|
||||||
extern char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag);
|
extern char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag);
|
||||||
|
37
lockfile.c
37
lockfile.c
@ -120,7 +120,7 @@ static char *resolve_symlink(char *p, size_t s)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure errno contains a meaningful value on error */
|
||||||
static int lock_file(struct lock_file *lk, const char *path, int flags)
|
static int lock_file(struct lock_file *lk, const char *path, int flags)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -129,8 +129,10 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
|
|||||||
*/
|
*/
|
||||||
static const size_t max_path_len = sizeof(lk->filename) - 5;
|
static const size_t max_path_len = sizeof(lk->filename) - 5;
|
||||||
|
|
||||||
if (strlen(path) >= max_path_len)
|
if (strlen(path) >= max_path_len) {
|
||||||
|
errno = ENAMETOOLONG;
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
strcpy(lk->filename, path);
|
strcpy(lk->filename, path);
|
||||||
if (!(flags & LOCK_NODEREF))
|
if (!(flags & LOCK_NODEREF))
|
||||||
resolve_symlink(lk->filename, max_path_len);
|
resolve_symlink(lk->filename, max_path_len);
|
||||||
@ -147,44 +149,51 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
|
|||||||
lock_file_list = lk;
|
lock_file_list = lk;
|
||||||
lk->on_list = 1;
|
lk->on_list = 1;
|
||||||
}
|
}
|
||||||
if (adjust_shared_perm(lk->filename))
|
if (adjust_shared_perm(lk->filename)) {
|
||||||
return error("cannot fix permission bits on %s",
|
int save_errno = errno;
|
||||||
|
error("cannot fix permission bits on %s",
|
||||||
lk->filename);
|
lk->filename);
|
||||||
|
errno = save_errno;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
lk->filename[0] = 0;
|
lk->filename[0] = 0;
|
||||||
return lk->fd;
|
return lk->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *unable_to_lock_message(const char *path, int err)
|
void unable_to_lock_message(const char *path, int err, struct strbuf *buf)
|
||||||
{
|
{
|
||||||
struct strbuf buf = STRBUF_INIT;
|
|
||||||
|
|
||||||
if (err == EEXIST) {
|
if (err == EEXIST) {
|
||||||
strbuf_addf(&buf, "Unable to create '%s.lock': %s.\n\n"
|
strbuf_addf(buf, "Unable to create '%s.lock': %s.\n\n"
|
||||||
"If no other git process is currently running, this probably means a\n"
|
"If no other git process is currently running, this probably means a\n"
|
||||||
"git process crashed in this repository earlier. Make sure no other git\n"
|
"git process crashed in this repository earlier. Make sure no other git\n"
|
||||||
"process is running and remove the file manually to continue.",
|
"process is running and remove the file manually to continue.",
|
||||||
absolute_path(path), strerror(err));
|
absolute_path(path), strerror(err));
|
||||||
} else
|
} else
|
||||||
strbuf_addf(&buf, "Unable to create '%s.lock': %s",
|
strbuf_addf(buf, "Unable to create '%s.lock': %s",
|
||||||
absolute_path(path), strerror(err));
|
absolute_path(path), strerror(err));
|
||||||
return strbuf_detach(&buf, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int unable_to_lock_error(const char *path, int err)
|
int unable_to_lock_error(const char *path, int err)
|
||||||
{
|
{
|
||||||
char *msg = unable_to_lock_message(path, err);
|
struct strbuf buf = STRBUF_INIT;
|
||||||
error("%s", msg);
|
|
||||||
free(msg);
|
unable_to_lock_message(path, err, &buf);
|
||||||
|
error("%s", buf.buf);
|
||||||
|
strbuf_release(&buf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
NORETURN void unable_to_lock_index_die(const char *path, int err)
|
NORETURN void unable_to_lock_index_die(const char *path, int err)
|
||||||
{
|
{
|
||||||
die("%s", unable_to_lock_message(path, err));
|
struct strbuf buf = STRBUF_INIT;
|
||||||
|
|
||||||
|
unable_to_lock_message(path, err, &buf);
|
||||||
|
die("%s", buf.buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This should return a meaningful errno on failure */
|
||||||
int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
|
int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
|
||||||
{
|
{
|
||||||
int fd = lock_file(lk, path, flags);
|
int fd = lock_file(lk, path, flags);
|
||||||
|
172
refs.c
172
refs.c
@ -1533,6 +1533,7 @@ static const char *handle_missing_loose_ref(const char *refname,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function needs to return a meaningful errno on failure */
|
||||||
const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int reading, int *flag)
|
const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int reading, int *flag)
|
||||||
{
|
{
|
||||||
int depth = MAXDEPTH;
|
int depth = MAXDEPTH;
|
||||||
@ -1543,8 +1544,10 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
|
|||||||
if (flag)
|
if (flag)
|
||||||
*flag = 0;
|
*flag = 0;
|
||||||
|
|
||||||
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
|
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
|
||||||
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
@ -1552,8 +1555,10 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
|
|||||||
char *buf;
|
char *buf;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
if (--depth < 0)
|
if (--depth < 0) {
|
||||||
|
errno = ELOOP;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
git_snpath(path, sizeof(path), "%s", refname);
|
git_snpath(path, sizeof(path), "%s", refname);
|
||||||
|
|
||||||
@ -1615,9 +1620,13 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
len = read_in_full(fd, buffer, sizeof(buffer)-1);
|
len = read_in_full(fd, buffer, sizeof(buffer)-1);
|
||||||
|
if (len < 0) {
|
||||||
|
int save_errno = errno;
|
||||||
close(fd);
|
close(fd);
|
||||||
if (len < 0)
|
errno = save_errno;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
while (len && isspace(buffer[len-1]))
|
while (len && isspace(buffer[len-1]))
|
||||||
len--;
|
len--;
|
||||||
buffer[len] = '\0';
|
buffer[len] = '\0';
|
||||||
@ -1634,6 +1643,7 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
|
|||||||
(buffer[40] != '\0' && !isspace(buffer[40]))) {
|
(buffer[40] != '\0' && !isspace(buffer[40]))) {
|
||||||
if (flag)
|
if (flag)
|
||||||
*flag |= REF_ISBROKEN;
|
*flag |= REF_ISBROKEN;
|
||||||
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return refname;
|
return refname;
|
||||||
@ -1646,6 +1656,7 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
|
|||||||
if (check_refname_format(buf, REFNAME_ALLOW_ONELEVEL)) {
|
if (check_refname_format(buf, REFNAME_ALLOW_ONELEVEL)) {
|
||||||
if (flag)
|
if (flag)
|
||||||
*flag |= REF_ISBROKEN;
|
*flag |= REF_ISBROKEN;
|
||||||
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
refname = strcpy(refname_buffer, buf);
|
refname = strcpy(refname_buffer, buf);
|
||||||
@ -2131,18 +2142,22 @@ int refname_match(const char *abbrev_name, const char *full_name)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function should make sure errno is meaningful on error */
|
||||||
static struct ref_lock *verify_lock(struct ref_lock *lock,
|
static struct ref_lock *verify_lock(struct ref_lock *lock,
|
||||||
const unsigned char *old_sha1, int mustexist)
|
const unsigned char *old_sha1, int mustexist)
|
||||||
{
|
{
|
||||||
if (read_ref_full(lock->ref_name, lock->old_sha1, mustexist, NULL)) {
|
if (read_ref_full(lock->ref_name, lock->old_sha1, mustexist, NULL)) {
|
||||||
|
int save_errno = errno;
|
||||||
error("Can't verify ref %s", lock->ref_name);
|
error("Can't verify ref %s", lock->ref_name);
|
||||||
unlock_ref(lock);
|
unlock_ref(lock);
|
||||||
|
errno = save_errno;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (hashcmp(lock->old_sha1, old_sha1)) {
|
if (hashcmp(lock->old_sha1, old_sha1)) {
|
||||||
error("Ref %s is at %s but expected %s", lock->ref_name,
|
error("Ref %s is at %s but expected %s", lock->ref_name,
|
||||||
sha1_to_hex(lock->old_sha1), sha1_to_hex(old_sha1));
|
sha1_to_hex(lock->old_sha1), sha1_to_hex(old_sha1));
|
||||||
unlock_ref(lock);
|
unlock_ref(lock);
|
||||||
|
errno = EBUSY;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return lock;
|
return lock;
|
||||||
@ -2155,14 +2170,16 @@ static int remove_empty_directories(const char *file)
|
|||||||
* only empty directories), remove them.
|
* only empty directories), remove them.
|
||||||
*/
|
*/
|
||||||
struct strbuf path;
|
struct strbuf path;
|
||||||
int result;
|
int result, save_errno;
|
||||||
|
|
||||||
strbuf_init(&path, 20);
|
strbuf_init(&path, 20);
|
||||||
strbuf_addstr(&path, file);
|
strbuf_addstr(&path, file);
|
||||||
|
|
||||||
result = remove_dir_recursively(&path, REMOVE_DIR_EMPTY_ONLY);
|
result = remove_dir_recursively(&path, REMOVE_DIR_EMPTY_ONLY);
|
||||||
|
save_errno = errno;
|
||||||
|
|
||||||
strbuf_release(&path);
|
strbuf_release(&path);
|
||||||
|
errno = save_errno;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -2251,6 +2268,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
|
|||||||
return logs_found;
|
return logs_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function should make sure errno is meaningful on error */
|
||||||
static struct ref_lock *lock_ref_sha1_basic(const char *refname,
|
static struct ref_lock *lock_ref_sha1_basic(const char *refname,
|
||||||
const unsigned char *old_sha1,
|
const unsigned char *old_sha1,
|
||||||
int flags, int *type_p)
|
int flags, int *type_p)
|
||||||
@ -2411,6 +2429,7 @@ static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This should return a meaningful errno on failure */
|
||||||
int lock_packed_refs(int flags)
|
int lock_packed_refs(int flags)
|
||||||
{
|
{
|
||||||
struct packed_ref_cache *packed_ref_cache;
|
struct packed_ref_cache *packed_ref_cache;
|
||||||
@ -2430,11 +2449,16 @@ int lock_packed_refs(int flags)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Commit the packed refs changes.
|
||||||
|
* On error we must make sure that errno contains a meaningful value.
|
||||||
|
*/
|
||||||
int commit_packed_refs(void)
|
int commit_packed_refs(void)
|
||||||
{
|
{
|
||||||
struct packed_ref_cache *packed_ref_cache =
|
struct packed_ref_cache *packed_ref_cache =
|
||||||
get_packed_ref_cache(&ref_cache);
|
get_packed_ref_cache(&ref_cache);
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
int save_errno = 0;
|
||||||
|
|
||||||
if (!packed_ref_cache->lock)
|
if (!packed_ref_cache->lock)
|
||||||
die("internal error: packed-refs not locked");
|
die("internal error: packed-refs not locked");
|
||||||
@ -2444,10 +2468,13 @@ int commit_packed_refs(void)
|
|||||||
do_for_each_entry_in_dir(get_packed_ref_dir(packed_ref_cache),
|
do_for_each_entry_in_dir(get_packed_ref_dir(packed_ref_cache),
|
||||||
0, write_packed_entry_fn,
|
0, write_packed_entry_fn,
|
||||||
&packed_ref_cache->lock->fd);
|
&packed_ref_cache->lock->fd);
|
||||||
if (commit_lock_file(packed_ref_cache->lock))
|
if (commit_lock_file(packed_ref_cache->lock)) {
|
||||||
|
save_errno = errno;
|
||||||
error = -1;
|
error = -1;
|
||||||
|
}
|
||||||
packed_ref_cache->lock = NULL;
|
packed_ref_cache->lock = NULL;
|
||||||
release_packed_ref_cache(packed_ref_cache);
|
release_packed_ref_cache(packed_ref_cache);
|
||||||
|
errno = save_errno;
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2654,12 +2681,12 @@ static int curate_packed_ref_fn(struct ref_entry *entry, void *cb_data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int repack_without_refs(const char **refnames, int n)
|
int repack_without_refs(const char **refnames, int n, struct strbuf *err)
|
||||||
{
|
{
|
||||||
struct ref_dir *packed;
|
struct ref_dir *packed;
|
||||||
struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
|
struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
|
||||||
struct string_list_item *ref_to_delete;
|
struct string_list_item *ref_to_delete;
|
||||||
int i, removed = 0;
|
int i, ret, removed = 0;
|
||||||
|
|
||||||
/* Look for a packed ref */
|
/* Look for a packed ref */
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
@ -2671,6 +2698,11 @@ int repack_without_refs(const char **refnames, int n)
|
|||||||
return 0; /* no refname exists in packed refs */
|
return 0; /* no refname exists in packed refs */
|
||||||
|
|
||||||
if (lock_packed_refs(0)) {
|
if (lock_packed_refs(0)) {
|
||||||
|
if (err) {
|
||||||
|
unable_to_lock_message(git_path("packed-refs"), errno,
|
||||||
|
err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
unable_to_lock_error(git_path("packed-refs"), errno);
|
unable_to_lock_error(git_path("packed-refs"), errno);
|
||||||
return error("cannot delete '%s' from packed refs", refnames[i]);
|
return error("cannot delete '%s' from packed refs", refnames[i]);
|
||||||
}
|
}
|
||||||
@ -2697,12 +2729,16 @@ int repack_without_refs(const char **refnames, int n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write what remains */
|
/* Write what remains */
|
||||||
return commit_packed_refs();
|
ret = commit_packed_refs();
|
||||||
|
if (ret && err)
|
||||||
|
strbuf_addf(err, "unable to overwrite old ref-pack file: %s",
|
||||||
|
strerror(errno));
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int repack_without_ref(const char *refname)
|
static int repack_without_ref(const char *refname)
|
||||||
{
|
{
|
||||||
return repack_without_refs(&refname, 1);
|
return repack_without_refs(&refname, 1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int delete_ref_loose(struct ref_lock *lock, int flag)
|
static int delete_ref_loose(struct ref_lock *lock, int flag)
|
||||||
@ -2940,6 +2976,7 @@ static int copy_msg(char *buf, const char *msg)
|
|||||||
return cp - buf;
|
return cp - buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function must set a meaningful errno on failure */
|
||||||
int log_ref_setup(const char *refname, char *logfile, int bufsize)
|
int log_ref_setup(const char *refname, char *logfile, int bufsize)
|
||||||
{
|
{
|
||||||
int logfd, oflags = O_APPEND | O_WRONLY;
|
int logfd, oflags = O_APPEND | O_WRONLY;
|
||||||
@ -2950,9 +2987,12 @@ int log_ref_setup(const char *refname, char *logfile, int bufsize)
|
|||||||
starts_with(refname, "refs/remotes/") ||
|
starts_with(refname, "refs/remotes/") ||
|
||||||
starts_with(refname, "refs/notes/") ||
|
starts_with(refname, "refs/notes/") ||
|
||||||
!strcmp(refname, "HEAD"))) {
|
!strcmp(refname, "HEAD"))) {
|
||||||
if (safe_create_leading_directories(logfile) < 0)
|
if (safe_create_leading_directories(logfile) < 0) {
|
||||||
return error("unable to create directory for %s",
|
int save_errno = errno;
|
||||||
logfile);
|
error("unable to create directory for %s", logfile);
|
||||||
|
errno = save_errno;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
oflags |= O_CREAT;
|
oflags |= O_CREAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2963,15 +3003,22 @@ int log_ref_setup(const char *refname, char *logfile, int bufsize)
|
|||||||
|
|
||||||
if ((oflags & O_CREAT) && errno == EISDIR) {
|
if ((oflags & O_CREAT) && errno == EISDIR) {
|
||||||
if (remove_empty_directories(logfile)) {
|
if (remove_empty_directories(logfile)) {
|
||||||
return error("There are still logs under '%s'",
|
int save_errno = errno;
|
||||||
|
error("There are still logs under '%s'",
|
||||||
logfile);
|
logfile);
|
||||||
|
errno = save_errno;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
logfd = open(logfile, oflags, 0666);
|
logfd = open(logfile, oflags, 0666);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logfd < 0)
|
if (logfd < 0) {
|
||||||
return error("Unable to append to %s: %s",
|
int save_errno = errno;
|
||||||
logfile, strerror(errno));
|
error("Unable to append to %s: %s", logfile,
|
||||||
|
strerror(errno));
|
||||||
|
errno = save_errno;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
adjust_shared_perm(logfile);
|
adjust_shared_perm(logfile);
|
||||||
@ -3011,8 +3058,19 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1,
|
|||||||
len += copy_msg(logrec + len - 1, msg) - 1;
|
len += copy_msg(logrec + len - 1, msg) - 1;
|
||||||
written = len <= maxlen ? write_in_full(logfd, logrec, len) : -1;
|
written = len <= maxlen ? write_in_full(logfd, logrec, len) : -1;
|
||||||
free(logrec);
|
free(logrec);
|
||||||
if (close(logfd) != 0 || written != len)
|
if (written != len) {
|
||||||
return error("Unable to append to %s", log_file);
|
int save_errno = errno;
|
||||||
|
close(logfd);
|
||||||
|
error("Unable to append to %s", log_file);
|
||||||
|
errno = save_errno;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (close(logfd)) {
|
||||||
|
int save_errno = errno;
|
||||||
|
error("Unable to append to %s", log_file);
|
||||||
|
errno = save_errno;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3021,14 +3079,17 @@ static int is_branch(const char *refname)
|
|||||||
return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/");
|
return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function must return a meaningful errno */
|
||||||
int write_ref_sha1(struct ref_lock *lock,
|
int write_ref_sha1(struct ref_lock *lock,
|
||||||
const unsigned char *sha1, const char *logmsg)
|
const unsigned char *sha1, const char *logmsg)
|
||||||
{
|
{
|
||||||
static char term = '\n';
|
static char term = '\n';
|
||||||
struct object *o;
|
struct object *o;
|
||||||
|
|
||||||
if (!lock)
|
if (!lock) {
|
||||||
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
if (!lock->force_write && !hashcmp(lock->old_sha1, sha1)) {
|
if (!lock->force_write && !hashcmp(lock->old_sha1, sha1)) {
|
||||||
unlock_ref(lock);
|
unlock_ref(lock);
|
||||||
return 0;
|
return 0;
|
||||||
@ -3038,19 +3099,23 @@ int write_ref_sha1(struct ref_lock *lock,
|
|||||||
error("Trying to write ref %s with nonexistent object %s",
|
error("Trying to write ref %s with nonexistent object %s",
|
||||||
lock->ref_name, sha1_to_hex(sha1));
|
lock->ref_name, sha1_to_hex(sha1));
|
||||||
unlock_ref(lock);
|
unlock_ref(lock);
|
||||||
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {
|
if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {
|
||||||
error("Trying to write non-commit object %s to branch %s",
|
error("Trying to write non-commit object %s to branch %s",
|
||||||
sha1_to_hex(sha1), lock->ref_name);
|
sha1_to_hex(sha1), lock->ref_name);
|
||||||
unlock_ref(lock);
|
unlock_ref(lock);
|
||||||
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (write_in_full(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 ||
|
if (write_in_full(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 ||
|
||||||
write_in_full(lock->lock_fd, &term, 1) != 1
|
write_in_full(lock->lock_fd, &term, 1) != 1 ||
|
||||||
|| close_ref(lock) < 0) {
|
close_ref(lock) < 0) {
|
||||||
|
int save_errno = errno;
|
||||||
error("Couldn't write %s", lock->lk->filename);
|
error("Couldn't write %s", lock->lk->filename);
|
||||||
unlock_ref(lock);
|
unlock_ref(lock);
|
||||||
|
errno = save_errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
clear_loose_ref_cache(&ref_cache);
|
clear_loose_ref_cache(&ref_cache);
|
||||||
@ -3487,10 +3552,13 @@ static struct ref_lock *update_ref_lock(const char *refname,
|
|||||||
|
|
||||||
static int update_ref_write(const char *action, const char *refname,
|
static int update_ref_write(const char *action, const char *refname,
|
||||||
const unsigned char *sha1, struct ref_lock *lock,
|
const unsigned char *sha1, struct ref_lock *lock,
|
||||||
enum action_on_err onerr)
|
struct strbuf *err, enum action_on_err onerr)
|
||||||
{
|
{
|
||||||
if (write_ref_sha1(lock, sha1, action) < 0) {
|
if (write_ref_sha1(lock, sha1, action) < 0) {
|
||||||
const char *str = "Cannot update the ref '%s'.";
|
const char *str = "Cannot update the ref '%s'.";
|
||||||
|
if (err)
|
||||||
|
strbuf_addf(err, str, refname);
|
||||||
|
|
||||||
switch (onerr) {
|
switch (onerr) {
|
||||||
case UPDATE_REFS_MSG_ON_ERR: error(str, refname); break;
|
case UPDATE_REFS_MSG_ON_ERR: error(str, refname); break;
|
||||||
case UPDATE_REFS_DIE_ON_ERR: die(str, refname); break;
|
case UPDATE_REFS_DIE_ON_ERR: die(str, refname); break;
|
||||||
@ -3533,10 +3601,13 @@ struct ref_transaction *ref_transaction_begin(void)
|
|||||||
return xcalloc(1, sizeof(struct ref_transaction));
|
return xcalloc(1, sizeof(struct ref_transaction));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ref_transaction_free(struct ref_transaction *transaction)
|
void ref_transaction_free(struct ref_transaction *transaction)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (!transaction)
|
||||||
|
return;
|
||||||
|
|
||||||
for (i = 0; i < transaction->nr; i++)
|
for (i = 0; i < transaction->nr; i++)
|
||||||
free(transaction->updates[i]);
|
free(transaction->updates[i]);
|
||||||
|
|
||||||
@ -3544,11 +3615,6 @@ static void ref_transaction_free(struct ref_transaction *transaction)
|
|||||||
free(transaction);
|
free(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ref_transaction_rollback(struct ref_transaction *transaction)
|
|
||||||
{
|
|
||||||
ref_transaction_free(transaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct ref_update *add_update(struct ref_transaction *transaction,
|
static struct ref_update *add_update(struct ref_transaction *transaction,
|
||||||
const char *refname)
|
const char *refname)
|
||||||
{
|
{
|
||||||
@ -3561,23 +3627,30 @@ static struct ref_update *add_update(struct ref_transaction *transaction,
|
|||||||
return update;
|
return update;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ref_transaction_update(struct ref_transaction *transaction,
|
int ref_transaction_update(struct ref_transaction *transaction,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
unsigned char *new_sha1, unsigned char *old_sha1,
|
const unsigned char *new_sha1,
|
||||||
int flags, int have_old)
|
const unsigned char *old_sha1,
|
||||||
|
int flags, int have_old,
|
||||||
|
struct strbuf *err)
|
||||||
{
|
{
|
||||||
struct ref_update *update = add_update(transaction, refname);
|
struct ref_update *update;
|
||||||
|
|
||||||
|
if (have_old && !old_sha1)
|
||||||
|
die("BUG: have_old is true but old_sha1 is NULL");
|
||||||
|
|
||||||
|
update = add_update(transaction, refname);
|
||||||
hashcpy(update->new_sha1, new_sha1);
|
hashcpy(update->new_sha1, new_sha1);
|
||||||
update->flags = flags;
|
update->flags = flags;
|
||||||
update->have_old = have_old;
|
update->have_old = have_old;
|
||||||
if (have_old)
|
if (have_old)
|
||||||
hashcpy(update->old_sha1, old_sha1);
|
hashcpy(update->old_sha1, old_sha1);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ref_transaction_create(struct ref_transaction *transaction,
|
void ref_transaction_create(struct ref_transaction *transaction,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
unsigned char *new_sha1,
|
const unsigned char *new_sha1,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
struct ref_update *update = add_update(transaction, refname);
|
struct ref_update *update = add_update(transaction, refname);
|
||||||
@ -3591,7 +3664,7 @@ void ref_transaction_create(struct ref_transaction *transaction,
|
|||||||
|
|
||||||
void ref_transaction_delete(struct ref_transaction *transaction,
|
void ref_transaction_delete(struct ref_transaction *transaction,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
unsigned char *old_sha1,
|
const unsigned char *old_sha1,
|
||||||
int flags, int have_old)
|
int flags, int have_old)
|
||||||
{
|
{
|
||||||
struct ref_update *update = add_update(transaction, refname);
|
struct ref_update *update = add_update(transaction, refname);
|
||||||
@ -3612,7 +3685,7 @@ int update_ref(const char *action, const char *refname,
|
|||||||
lock = update_ref_lock(refname, oldval, flags, NULL, onerr);
|
lock = update_ref_lock(refname, oldval, flags, NULL, onerr);
|
||||||
if (!lock)
|
if (!lock)
|
||||||
return 1;
|
return 1;
|
||||||
return update_ref_write(action, refname, sha1, lock, onerr);
|
return update_ref_write(action, refname, sha1, lock, NULL, onerr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ref_update_compare(const void *r1, const void *r2)
|
static int ref_update_compare(const void *r1, const void *r2)
|
||||||
@ -3623,28 +3696,23 @@ static int ref_update_compare(const void *r1, const void *r2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int ref_update_reject_duplicates(struct ref_update **updates, int n,
|
static int ref_update_reject_duplicates(struct ref_update **updates, int n,
|
||||||
enum action_on_err onerr)
|
struct strbuf *err)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 1; i < n; i++)
|
for (i = 1; i < n; i++)
|
||||||
if (!strcmp(updates[i - 1]->refname, updates[i]->refname)) {
|
if (!strcmp(updates[i - 1]->refname, updates[i]->refname)) {
|
||||||
const char *str =
|
const char *str =
|
||||||
"Multiple updates for ref '%s' not allowed.";
|
"Multiple updates for ref '%s' not allowed.";
|
||||||
switch (onerr) {
|
if (err)
|
||||||
case UPDATE_REFS_MSG_ON_ERR:
|
strbuf_addf(err, str, updates[i]->refname);
|
||||||
error(str, updates[i]->refname); break;
|
|
||||||
case UPDATE_REFS_DIE_ON_ERR:
|
|
||||||
die(str, updates[i]->refname); break;
|
|
||||||
case UPDATE_REFS_QUIET_ON_ERR:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ref_transaction_commit(struct ref_transaction *transaction,
|
int ref_transaction_commit(struct ref_transaction *transaction,
|
||||||
const char *msg, enum action_on_err onerr)
|
const char *msg, struct strbuf *err)
|
||||||
{
|
{
|
||||||
int ret = 0, delnum = 0, i;
|
int ret = 0, delnum = 0, i;
|
||||||
const char **delnames;
|
const char **delnames;
|
||||||
@ -3659,7 +3727,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
|||||||
|
|
||||||
/* Copy, sort, and reject duplicate refs */
|
/* Copy, sort, and reject duplicate refs */
|
||||||
qsort(updates, n, sizeof(*updates), ref_update_compare);
|
qsort(updates, n, sizeof(*updates), ref_update_compare);
|
||||||
ret = ref_update_reject_duplicates(updates, n, onerr);
|
ret = ref_update_reject_duplicates(updates, n, err);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -3671,8 +3739,12 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
|||||||
(update->have_old ?
|
(update->have_old ?
|
||||||
update->old_sha1 : NULL),
|
update->old_sha1 : NULL),
|
||||||
update->flags,
|
update->flags,
|
||||||
&update->type, onerr);
|
&update->type,
|
||||||
|
UPDATE_REFS_QUIET_ON_ERR);
|
||||||
if (!update->lock) {
|
if (!update->lock) {
|
||||||
|
if (err)
|
||||||
|
strbuf_addf(err, "Cannot lock the ref '%s'.",
|
||||||
|
update->refname);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -3686,7 +3758,8 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
|||||||
ret = update_ref_write(msg,
|
ret = update_ref_write(msg,
|
||||||
update->refname,
|
update->refname,
|
||||||
update->new_sha1,
|
update->new_sha1,
|
||||||
update->lock, onerr);
|
update->lock, err,
|
||||||
|
UPDATE_REFS_QUIET_ON_ERR);
|
||||||
update->lock = NULL; /* freed by update_ref_write */
|
update->lock = NULL; /* freed by update_ref_write */
|
||||||
if (ret)
|
if (ret)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -3703,7 +3776,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret |= repack_without_refs(delnames, delnum);
|
ret |= repack_without_refs(delnames, delnum, err);
|
||||||
for (i = 0; i < delnum; i++)
|
for (i = 0; i < delnum; i++)
|
||||||
unlink_or_warn(git_path("logs/%s", delnames[i]));
|
unlink_or_warn(git_path("logs/%s", delnames[i]));
|
||||||
clear_loose_ref_cache(&ref_cache);
|
clear_loose_ref_cache(&ref_cache);
|
||||||
@ -3713,7 +3786,6 @@ cleanup:
|
|||||||
if (updates[i]->lock)
|
if (updates[i]->lock)
|
||||||
unlock_ref(updates[i]->lock);
|
unlock_ref(updates[i]->lock);
|
||||||
free(delnames);
|
free(delnames);
|
||||||
ref_transaction_free(transaction);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
51
refs.h
51
refs.h
@ -82,6 +82,7 @@ extern void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct st
|
|||||||
/*
|
/*
|
||||||
* Lock the packed-refs file for writing. Flags is passed to
|
* Lock the packed-refs file for writing. Flags is passed to
|
||||||
* hold_lock_file_for_update(). Return 0 on success.
|
* hold_lock_file_for_update(). Return 0 on success.
|
||||||
|
* Errno is set to something meaningful on error.
|
||||||
*/
|
*/
|
||||||
extern int lock_packed_refs(int flags);
|
extern int lock_packed_refs(int flags);
|
||||||
|
|
||||||
@ -97,6 +98,7 @@ extern void add_packed_ref(const char *refname, const unsigned char *sha1);
|
|||||||
* Write the current version of the packed refs cache from memory to
|
* Write the current version of the packed refs cache from memory to
|
||||||
* disk. The packed-refs file must already be locked for writing (see
|
* disk. The packed-refs file must already be locked for writing (see
|
||||||
* lock_packed_refs()). Return zero on success.
|
* lock_packed_refs()). Return zero on success.
|
||||||
|
* Sets errno to something meaningful on error.
|
||||||
*/
|
*/
|
||||||
extern int commit_packed_refs(void);
|
extern int commit_packed_refs(void);
|
||||||
|
|
||||||
@ -121,7 +123,8 @@ extern void rollback_packed_refs(void);
|
|||||||
*/
|
*/
|
||||||
int pack_refs(unsigned int flags);
|
int pack_refs(unsigned int flags);
|
||||||
|
|
||||||
extern int repack_without_refs(const char **refnames, int n);
|
extern int repack_without_refs(const char **refnames, int n,
|
||||||
|
struct strbuf *err);
|
||||||
|
|
||||||
extern int ref_exists(const char *);
|
extern int ref_exists(const char *);
|
||||||
|
|
||||||
@ -135,11 +138,15 @@ extern int ref_exists(const char *);
|
|||||||
*/
|
*/
|
||||||
extern int peel_ref(const char *refname, unsigned char *sha1);
|
extern int peel_ref(const char *refname, unsigned char *sha1);
|
||||||
|
|
||||||
/** Locks a "refs/" ref returning the lock on success and NULL on failure. **/
|
/*
|
||||||
|
* Locks a "refs/" ref returning the lock on success and NULL on failure.
|
||||||
|
* On failure errno is set to something meaningful.
|
||||||
|
*/
|
||||||
extern struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char *old_sha1);
|
extern struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char *old_sha1);
|
||||||
|
|
||||||
/** Locks any ref (for 'HEAD' type refs). */
|
/** Locks any ref (for 'HEAD' type refs). */
|
||||||
#define REF_NODEREF 0x01
|
#define REF_NODEREF 0x01
|
||||||
|
/* errno is set to something meaningful on failure */
|
||||||
extern struct ref_lock *lock_any_ref_for_update(const char *refname,
|
extern struct ref_lock *lock_any_ref_for_update(const char *refname,
|
||||||
const unsigned char *old_sha1,
|
const unsigned char *old_sha1,
|
||||||
int flags, int *type_p);
|
int flags, int *type_p);
|
||||||
@ -156,7 +163,9 @@ extern void unlock_ref(struct ref_lock *lock);
|
|||||||
/** Writes sha1 into the ref specified by the lock. **/
|
/** Writes sha1 into the ref specified by the lock. **/
|
||||||
extern int write_ref_sha1(struct ref_lock *lock, const unsigned char *sha1, const char *msg);
|
extern int write_ref_sha1(struct ref_lock *lock, const unsigned char *sha1, const char *msg);
|
||||||
|
|
||||||
/** Setup reflog before using. **/
|
/*
|
||||||
|
* Setup reflog before using. Set errno to something meaningful on failure.
|
||||||
|
*/
|
||||||
int log_ref_setup(const char *refname, char *logfile, int bufsize);
|
int log_ref_setup(const char *refname, char *logfile, int bufsize);
|
||||||
|
|
||||||
/** Reads log for the value of ref during at_time. **/
|
/** Reads log for the value of ref during at_time. **/
|
||||||
@ -219,17 +228,10 @@ enum action_on_err {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Begin a reference transaction. The reference transaction must
|
* Begin a reference transaction. The reference transaction must
|
||||||
* eventually be commited using ref_transaction_commit() or rolled
|
* be freed by calling ref_transaction_free().
|
||||||
* back using ref_transaction_rollback().
|
|
||||||
*/
|
*/
|
||||||
struct ref_transaction *ref_transaction_begin(void);
|
struct ref_transaction *ref_transaction_begin(void);
|
||||||
|
|
||||||
/*
|
|
||||||
* Roll back a ref_transaction and free all associated data.
|
|
||||||
*/
|
|
||||||
void ref_transaction_rollback(struct ref_transaction *transaction);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following functions add a reference check or update to a
|
* The following functions add a reference check or update to a
|
||||||
* ref_transaction. In all of them, refname is the name of the
|
* ref_transaction. In all of them, refname is the name of the
|
||||||
@ -238,18 +240,22 @@ void ref_transaction_rollback(struct ref_transaction *transaction);
|
|||||||
* can be REF_NODEREF; it is passed to update_ref_lock().
|
* can be REF_NODEREF; it is passed to update_ref_lock().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a reference update to transaction. new_sha1 is the value that
|
* Add a reference update to transaction. new_sha1 is the value that
|
||||||
* the reference should have after the update, or zeros if it should
|
* the reference should have after the update, or zeros if it should
|
||||||
* be deleted. If have_old is true, then old_sha1 holds the value
|
* be deleted. If have_old is true, then old_sha1 holds the value
|
||||||
* that the reference should have had before the update, or zeros if
|
* that the reference should have had before the update, or zeros if
|
||||||
* it must not have existed beforehand.
|
* it must not have existed beforehand.
|
||||||
|
* Function returns 0 on success and non-zero on failure. A failure to update
|
||||||
|
* means that the transaction as a whole has failed and will need to be
|
||||||
|
* rolled back. On failure the err buffer will be updated.
|
||||||
*/
|
*/
|
||||||
void ref_transaction_update(struct ref_transaction *transaction,
|
int ref_transaction_update(struct ref_transaction *transaction,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
unsigned char *new_sha1, unsigned char *old_sha1,
|
const unsigned char *new_sha1,
|
||||||
int flags, int have_old);
|
const unsigned char *old_sha1,
|
||||||
|
int flags, int have_old,
|
||||||
|
struct strbuf *err);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a reference creation to transaction. new_sha1 is the value
|
* Add a reference creation to transaction. new_sha1 is the value
|
||||||
@ -259,7 +265,7 @@ void ref_transaction_update(struct ref_transaction *transaction,
|
|||||||
*/
|
*/
|
||||||
void ref_transaction_create(struct ref_transaction *transaction,
|
void ref_transaction_create(struct ref_transaction *transaction,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
unsigned char *new_sha1,
|
const unsigned char *new_sha1,
|
||||||
int flags);
|
int flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -269,16 +275,23 @@ void ref_transaction_create(struct ref_transaction *transaction,
|
|||||||
*/
|
*/
|
||||||
void ref_transaction_delete(struct ref_transaction *transaction,
|
void ref_transaction_delete(struct ref_transaction *transaction,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
unsigned char *old_sha1,
|
const unsigned char *old_sha1,
|
||||||
int flags, int have_old);
|
int flags, int have_old);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Commit all of the changes that have been queued in transaction, as
|
* Commit all of the changes that have been queued in transaction, as
|
||||||
* atomically as possible. Return a nonzero value if there is a
|
* atomically as possible. Return a nonzero value if there is a
|
||||||
* problem. The ref_transaction is freed by this function.
|
* problem.
|
||||||
|
* If err is non-NULL we will add an error string to it to explain why
|
||||||
|
* the transaction failed. The string does not end in newline.
|
||||||
*/
|
*/
|
||||||
int ref_transaction_commit(struct ref_transaction *transaction,
|
int ref_transaction_commit(struct ref_transaction *transaction,
|
||||||
const char *msg, enum action_on_err onerr);
|
const char *msg, struct strbuf *err);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free an existing transaction and all associated data.
|
||||||
|
*/
|
||||||
|
void ref_transaction_free(struct ref_transaction *transaction);
|
||||||
|
|
||||||
/** Lock a ref and then write its file */
|
/** Lock a ref and then write its file */
|
||||||
int update_ref(const char *action, const char *refname,
|
int update_ref(const char *action, const char *refname,
|
||||||
|
Loading…
Reference in New Issue
Block a user