add_update(): initialize the whole ref_update
[gitweb.git] / refs / files-backend.c
index c41cf432d13f203a2f3796fc21b7732f8b5750c5..1d1b72d57d1c895280e54e79d0e52192a70094de 100644 (file)
@@ -1388,44 +1388,6 @@ static int resolve_missing_loose_ref(const char *refname,
        return -1;
 }
 
-/*
- * Read the specified reference from the filesystem or packed refs
- * file, non-recursively. Set type to describe the reference, and:
- *
- * - If refname is the name of a normal reference, fill in sha1
- *   (leaving referent unchanged).
- *
- * - If refname is the name of a symbolic reference, write the full
- *   name of the reference to which it refers (e.g.
- *   "refs/heads/master") to referent and set the REF_ISSYMREF bit in
- *   type (leaving sha1 unchanged). The caller is responsible for
- *   validating that referent is a valid reference name.
- *
- * WARNING: refname might be used as part of a filename, so it is
- * important from a security standpoint that it be safe in the sense
- * of refname_is_safe(). Moreover, for symrefs this function sets
- * referent to whatever the repository says, which might not be a
- * properly-formatted or even safe reference name. NEITHER INPUT NOR
- * OUTPUT REFERENCE NAMES ARE VALIDATED WITHIN THIS FUNCTION.
- *
- * Return 0 on success. If the ref doesn't exist, set errno to ENOENT
- * and return -1. If the ref exists but is neither a symbolic ref nor
- * a sha1, it is broken; set REF_ISBROKEN in type, set errno to
- * EINVAL, and return -1. If there is another error reading the ref,
- * set errno appropriately and return -1.
- *
- * Backend-specific flags might be set in type as well, regardless of
- * outcome.
- *
- * It is OK for refname to point into referent. If so:
- *
- * - if the function succeeds with REF_ISSYMREF, referent will be
- *   overwritten and the memory formerly pointed to by it might be
- *   changed or even freed.
- *
- * - in all other cases, referent will be untouched, and therefore
- *   refname will still be valid and unchanged.
- */
 int read_raw_ref(const char *refname, unsigned char *sha1,
                 struct strbuf *referent, unsigned int *type)
 {
@@ -1739,7 +1701,7 @@ static int verify_lock(struct ref_lock *lock,
                          lock->old_oid.hash, NULL)) {
                if (old_sha1) {
                        int save_errno = errno;
-                       strbuf_addf(err, "can't verify ref %s", lock->ref_name);
+                       strbuf_addf(err, "can't verify ref '%s'", lock->ref_name);
                        errno = save_errno;
                        return -1;
                } else {
@@ -1748,7 +1710,7 @@ static int verify_lock(struct ref_lock *lock,
                }
        }
        if (old_sha1 && hashcmp(lock->old_oid.hash, old_sha1)) {
-               strbuf_addf(err, "ref %s is at %s but expected %s",
+               strbuf_addf(err, "ref '%s' is at %s but expected %s",
                            lock->ref_name,
                            sha1_to_hex(lock->old_oid.hash),
                            sha1_to_hex(old_sha1));
@@ -1776,7 +1738,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
                                            const unsigned char *old_sha1,
                                            const struct string_list *extras,
                                            const struct string_list *skip,
-                                           unsigned int flags, int *type_p,
+                                           unsigned int flags, int *type,
                                            struct strbuf *err)
 {
        struct strbuf ref_file = STRBUF_INIT;
@@ -1784,7 +1746,6 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
        const char *orig_refname = refname;
        struct ref_lock *lock;
        int last_errno = 0;
-       int type;
        int lflags = 0;
        int mustexist = (old_sha1 && !is_null_sha1(old_sha1));
        int resolve_flags = 0;
@@ -1804,7 +1765,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
        }
 
        refname = resolve_ref_unsafe(refname, resolve_flags,
-                                    lock->old_oid.hash, &type);
+                                    lock->old_oid.hash, type);
        if (!refname && errno == EISDIR) {
                /*
                 * we are trying to lock foo but we used to
@@ -1822,16 +1783,14 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
                        goto error_return;
                }
                refname = resolve_ref_unsafe(orig_refname, resolve_flags,
-                                            lock->old_oid.hash, &type);
+                                            lock->old_oid.hash, type);
        }
-       if (type_p)
-           *type_p = type;
        if (!refname) {
                last_errno = errno;
                if (last_errno != ENOTDIR ||
                    !verify_refname_available_dir(orig_refname, extras, skip,
                                                  get_loose_refs(&ref_cache), err))
-                       strbuf_addf(err, "unable to resolve reference %s: %s",
+                       strbuf_addf(err, "unable to resolve reference '%s': %s",
                                    orig_refname, strerror(last_errno));
 
                goto error_return;
@@ -1869,7 +1828,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
                /* fall through */
        default:
                last_errno = errno;
-               strbuf_addf(err, "unable to create directory for %s",
+               strbuf_addf(err, "unable to create directory for '%s'",
                            ref_file.buf);
                goto error_return;
        }
@@ -2128,7 +2087,7 @@ static void prune_ref(struct ref_to_prune *r)
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_delete(transaction, r->name, r->sha1,
-                                  REF_ISPRUNING, NULL, &err) ||
+                                  REF_ISPRUNING | REF_NODEREF, NULL, &err) ||
            ref_transaction_commit(transaction, &err)) {
                ref_transaction_free(transaction);
                error("%s", err.buf);
@@ -2340,8 +2299,8 @@ static int rename_tmp_log(const char *newrefname)
 }
 
 int verify_refname_available(const char *newname,
-                            struct string_list *extras,
-                            struct string_list *skip,
+                            const struct string_list *extras,
+                            const struct string_list *skip,
                             struct strbuf *err)
 {
        struct ref_dir *packed_refs = get_packed_refs(&ref_cache);
@@ -2374,7 +2333,8 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
        if (log && S_ISLNK(loginfo.st_mode))
                return error("reflog for %s is a symlink", oldrefname);
 
-       if (!resolve_ref_unsafe(oldrefname, RESOLVE_REF_READING, orig_sha1, &flag))
+       if (!resolve_ref_unsafe(oldrefname, RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
+                               orig_sha1, &flag))
                return error("refname %s not found", oldrefname);
 
        if (flag & REF_ISSYMREF)
@@ -2392,8 +2352,16 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
                goto rollback;
        }
 
-       if (!read_ref_full(newrefname, RESOLVE_REF_READING, sha1, NULL) &&
-           delete_ref(newrefname, sha1, REF_NODEREF)) {
+       /*
+        * Since we are doing a shallow lookup, sha1 is not the
+        * correct value to pass to delete_ref as old_sha1. But that
+        * doesn't matter, because an old_sha1 check wouldn't add to
+        * the safety anyway; we want to delete the reference whatever
+        * its current value.
+        */
+       if (!read_ref_full(newrefname, RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
+                          sha1, NULL) &&
+           delete_ref(newrefname, NULL, REF_NODEREF)) {
                if (errno==EISDIR) {
                        struct strbuf path = STRBUF_INIT;
                        int result;
@@ -2417,7 +2385,8 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
 
        logmoved = log;
 
-       lock = lock_ref_sha1_basic(newrefname, NULL, NULL, NULL, 0, NULL, &err);
+       lock = lock_ref_sha1_basic(newrefname, NULL, NULL, NULL, REF_NODEREF,
+                                  NULL, &err);
        if (!lock) {
                error("unable to rename '%s' to '%s': %s", oldrefname, newrefname, err.buf);
                strbuf_release(&err);
@@ -2435,7 +2404,8 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
        return 0;
 
  rollback:
-       lock = lock_ref_sha1_basic(oldrefname, NULL, NULL, NULL, 0, NULL, &err);
+       lock = lock_ref_sha1_basic(oldrefname, NULL, NULL, NULL, REF_NODEREF,
+                                  NULL, &err);
        if (!lock) {
                error("unable to lock %s for rollback: %s", oldrefname, err.buf);
                strbuf_release(&err);
@@ -2514,7 +2484,7 @@ static int log_ref_setup(const char *refname, struct strbuf *logfile, struct str
        strbuf_git_path(logfile, "logs/%s", refname);
        if (force_create || should_autocreate_reflog(refname)) {
                if (safe_create_leading_directories(logfile->buf) < 0) {
-                       strbuf_addf(err, "unable to create directory for %s: "
+                       strbuf_addf(err, "unable to create directory for '%s': "
                                    "%s", logfile->buf, strerror(errno));
                        return -1;
                }
@@ -2528,7 +2498,7 @@ static int log_ref_setup(const char *refname, struct strbuf *logfile, struct str
 
                if (errno == EISDIR) {
                        if (remove_empty_directories(logfile)) {
-                               strbuf_addf(err, "There are still logs under "
+                               strbuf_addf(err, "there are still logs under "
                                            "'%s'", logfile->buf);
                                return -1;
                        }
@@ -2536,7 +2506,7 @@ static int log_ref_setup(const char *refname, struct strbuf *logfile, struct str
                }
 
                if (logfd < 0) {
-                       strbuf_addf(err, "unable to append to %s: %s",
+                       strbuf_addf(err, "unable to append to '%s': %s",
                                    logfile->buf, strerror(errno));
                        return -1;
                }
@@ -2605,13 +2575,13 @@ static int log_ref_write_1(const char *refname, const unsigned char *old_sha1,
        result = log_ref_write_fd(logfd, old_sha1, new_sha1,
                                  git_committer_info(0), msg);
        if (result) {
-               strbuf_addf(err, "unable to append to %s: %s", logfile->buf,
+               strbuf_addf(err, "unable to append to '%s': %s", logfile->buf,
                            strerror(errno));
                close(logfd);
                return -1;
        }
        if (close(logfd)) {
-               strbuf_addf(err, "unable to append to %s: %s", logfile->buf,
+               strbuf_addf(err, "unable to append to '%s': %s", logfile->buf,
                            strerror(errno));
                return -1;
        }
@@ -2652,14 +2622,14 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
        o = parse_object(sha1);
        if (!o) {
                strbuf_addf(err,
-                           "Trying to write ref %s with nonexistent object %s",
+                           "trying to write ref '%s' with nonexistent object %s",
                            lock->ref_name, sha1_to_hex(sha1));
                unlock_ref(lock);
                return -1;
        }
        if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {
                strbuf_addf(err,
-                           "Trying to write non-commit object %s to branch %s",
+                           "trying to write non-commit object %s to branch '%s'",
                            sha1_to_hex(sha1), lock->ref_name);
                unlock_ref(lock);
                return -1;
@@ -2669,7 +2639,7 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
            write_in_full(fd, &term, 1) != 1 ||
            close_ref(lock) < 0) {
                strbuf_addf(err,
-                           "Couldn't write %s", get_lock_file_path(lock->lk));
+                           "couldn't write '%s'", get_lock_file_path(lock->lk));
                unlock_ref(lock);
                return -1;
        }
@@ -2690,7 +2660,7 @@ static int commit_ref_update(struct ref_lock *lock,
            (strcmp(lock->ref_name, lock->orig_ref_name) &&
             log_ref_write(lock->orig_ref_name, lock->old_oid.hash, sha1, logmsg, flags, err) < 0)) {
                char *old_msg = strbuf_detach(err, NULL);
-               strbuf_addf(err, "Cannot update the ref '%s': %s",
+               strbuf_addf(err, "cannot update the ref '%s': %s",
                            lock->ref_name, old_msg);
                free(old_msg);
                unlock_ref(lock);
@@ -2724,8 +2694,8 @@ static int commit_ref_update(struct ref_lock *lock,
                        }
                }
        }
-       if (commit_ref(lock)) {
-               strbuf_addf(err, "Couldn't set %s", lock->ref_name);
+       if (!(flags & REF_LOG_ONLY) && commit_ref(lock)) {
+               strbuf_addf(err, "couldn't set '%s'", lock->ref_name);
                unlock_ref(lock);
                return -1;
        }
@@ -3074,7 +3044,7 @@ static int ref_update_reject_duplicates(struct string_list *refnames,
        for (i = 1; i < n; i++)
                if (!strcmp(refnames->items[i - 1].string, refnames->items[i].string)) {
                        strbuf_addf(err,
-                                   "Multiple updates for ref '%s' not allowed.",
+                                   "multiple updates for ref '%s' not allowed.",
                                    refnames->items[i].string);
                        return 1;
                }
@@ -3142,7 +3112,8 @@ int ref_transaction_commit(struct ref_transaction *transaction,
                        goto cleanup;
                }
                if ((update->flags & REF_HAVE_NEW) &&
-                   !(update->flags & REF_DELETING)) {
+                   !(update->flags & REF_DELETING) &&
+                   !(update->flags & REF_LOG_ONLY)) {
                        int overwriting_symref = ((update->type & REF_ISSYMREF) &&
                                                  (update->flags & REF_NODEREF));
 
@@ -3174,12 +3145,14 @@ int ref_transaction_commit(struct ref_transaction *transaction,
                }
                if (!(update->flags & REF_NEEDS_COMMIT)) {
                        /*
-                        * We didn't have to write anything to the lockfile.
-                        * Close it to free up the file descriptor:
+                        * We didn't call write_ref_to_lockfile(), so
+                        * the lockfile is still open. Close it to
+                        * free up the file descriptor:
                         */
                        if (close_ref(update->lock)) {
-                               strbuf_addf(err, "Couldn't close %s.lock",
+                               strbuf_addf(err, "couldn't close '%s.lock'",
                                            update->refname);
+                               ret = TRANSACTION_GENERIC_ERROR;
                                goto cleanup;
                        }
                }
@@ -3189,7 +3162,8 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        for (i = 0; i < transaction->nr; i++) {
                struct ref_update *update = transaction->updates[i];
 
-               if (update->flags & REF_NEEDS_COMMIT) {
+               if (update->flags & REF_NEEDS_COMMIT ||
+                   update->flags & REF_LOG_ONLY) {
                        if (commit_ref_update(update->lock,
                                              update->new_sha1, update->msg,
                                              update->flags, err)) {
@@ -3208,7 +3182,8 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        for (i = 0; i < transaction->nr; i++) {
                struct ref_update *update = transaction->updates[i];
 
-               if (update->flags & REF_DELETING) {
+               if (update->flags & REF_DELETING &&
+                   !(update->flags & REF_LOG_ONLY)) {
                        if (delete_ref_loose(update->lock, update->type, err)) {
                                ret = TRANSACTION_GENERIC_ERROR;
                                goto cleanup;