refs.c: log_ref_write should try to return meaningful errno

Making errno from write_ref_sha1() meaningful, which should fix

* a bug in "git checkout -b" where it prints strerror(errno)
  despite errno possibly being zero or clobbered

* a bug in "git fetch"'s s_update_ref, which trusts the result of an
  errno == ENOTDIR check to detect D/F conflicts

Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Acked-by: Michael Haggerty <mhagger@alum.mit.edu>
This commit is contained in:
Ronnie Sahlberg 2014-06-20 07:42:55 -07:00 committed by Junio C Hamano
parent 76d70dc0c6
commit dc615de861

28
refs.c
View File

@ -2859,8 +2859,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;
} }
@ -2869,14 +2880,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;
@ -2886,19 +2900,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);