sha1_file: introduce an nth_packed_object_oid function
[gitweb.git] / refs / files-backend.c
index 0709f60b8e8c43fa830c0e678fdf7b83435535bb..fea20e99fe1d2f0b68d318eafc4c3b807722c232 100644 (file)
@@ -501,7 +501,7 @@ static void sort_ref_dir(struct ref_dir *dir)
        if (dir->sorted == dir->nr)
                return;
 
-       qsort(dir->entries, dir->nr, sizeof(*dir->entries), ref_entry_cmp);
+       QSORT(dir->entries, dir->nr, ref_entry_cmp);
 
        /* Remove any duplicates: */
        for (i = 0, j = 0; j < dir->nr; j++) {
@@ -697,7 +697,7 @@ static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator,
 
        if (peel_entry(entry, 0))
                return -1;
-       hashcpy(peeled->hash, entry->u.value.peeled.hash);
+       oidcpy(peeled, &entry->u.value.peeled);
        return 0;
 }
 
@@ -1353,6 +1353,7 @@ static int files_read_raw_ref(struct ref_store *ref_store,
        int fd;
        int ret = -1;
        int save_errno;
+       int remaining_retries = 3;
 
        *type = 0;
        strbuf_reset(&sb_path);
@@ -1373,8 +1374,14 @@ static int files_read_raw_ref(struct ref_store *ref_store,
         * <-> symlink) between the lstat() and reading, then
         * we don't want to report that as an error but rather
         * try again starting with the lstat().
+        *
+        * We'll keep a count of the retries, though, just to avoid
+        * any confusing situation sending us into an infinite loop.
         */
 
+       if (remaining_retries-- <= 0)
+               goto out;
+
        if (lstat(path, &st) < 0) {
                if (errno != ENOENT)
                        goto out;
@@ -1403,6 +1410,11 @@ static int files_read_raw_ref(struct ref_store *ref_store,
                        ret = 0;
                        goto out;
                }
+               /*
+                * It doesn't look like a refname; fall through to just
+                * treating it like a non-symlink, and reading whatever it
+                * points to.
+                */
        }
 
        /* Is it a directory? */
@@ -1426,7 +1438,7 @@ static int files_read_raw_ref(struct ref_store *ref_store,
         */
        fd = open(path, O_RDONLY);
        if (fd < 0) {
-               if (errno == ENOENT)
+               if (errno == ENOENT && !S_ISLNK(st.st_mode))
                        /* inconsistent with lstat; retry */
                        goto stat_ref;
                else
@@ -2670,7 +2682,7 @@ static int files_rename_ref(struct ref_store *ref_store,
        }
 
        flag = log_all_ref_updates;
-       log_all_ref_updates = 0;
+       log_all_ref_updates = LOG_REFS_NONE;
        if (write_ref_to_lockfile(lock, orig_sha1, &err) ||
            commit_ref_update(refs, lock, orig_sha1, NULL, &err)) {
                error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
@@ -2823,8 +2835,8 @@ static int log_ref_write_1(const char *refname, const unsigned char *old_sha1,
 {
        int logfd, result, oflags = O_APPEND | O_WRONLY;
 
-       if (log_all_ref_updates < 0)
-               log_all_ref_updates = !is_bare_repository();
+       if (log_all_ref_updates == LOG_REFS_UNSET)
+               log_all_ref_updates = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
 
        result = log_ref_setup(refname, logfile, err, flags & REF_FORCE_CREATE_REFLOG);
 
@@ -3101,16 +3113,17 @@ static int files_delete_reflog(struct ref_store *ref_store,
 
 static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *cb_data)
 {
-       unsigned char osha1[20], nsha1[20];
+       struct object_id ooid, noid;
        char *email_end, *message;
        unsigned long timestamp;
        int tz;
+       const char *p = sb->buf;
 
        /* old SP new SP name <email> SP time TAB msg LF */
-       if (sb->len < 83 || sb->buf[sb->len - 1] != '\n' ||
-           get_sha1_hex(sb->buf, osha1) || sb->buf[40] != ' ' ||
-           get_sha1_hex(sb->buf + 41, nsha1) || sb->buf[81] != ' ' ||
-           !(email_end = strchr(sb->buf + 82, '>')) ||
+       if (!sb->len || sb->buf[sb->len - 1] != '\n' ||
+           parse_oid_hex(p, &ooid, &p) || *p++ != ' ' ||
+           parse_oid_hex(p, &noid, &p) || *p++ != ' ' ||
+           !(email_end = strchr(p, '>')) ||
            email_end[1] != ' ' ||
            !(timestamp = strtoul(email_end + 2, &message, 10)) ||
            !message || message[0] != ' ' ||
@@ -3124,7 +3137,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c
                message += 6;
        else
                message += 7;
-       return fn(osha1, nsha1, sb->buf + 82, timestamp, tz, message, cb_data);
+       return fn(&ooid, &noid, p, timestamp, tz, message, cb_data);
 }
 
 static char *find_beginning_of_line(char *bob, char *scan)
@@ -3924,10 +3937,10 @@ struct expire_reflog_cb {
        reflog_expiry_should_prune_fn *should_prune_fn;
        void *policy_cb;
        FILE *newlog;
-       unsigned char last_kept_sha1[20];
+       struct object_id last_kept_oid;
 };
 
-static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
                             const char *email, unsigned long timestamp, int tz,
                             const char *message, void *cb_data)
 {
@@ -3935,9 +3948,9 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
        struct expire_reflog_policy_cb *policy_cb = cb->policy_cb;
 
        if (cb->flags & EXPIRE_REFLOGS_REWRITE)
-               osha1 = cb->last_kept_sha1;
+               ooid = &cb->last_kept_oid;
 
-       if ((*cb->should_prune_fn)(osha1, nsha1, email, timestamp, tz,
+       if ((*cb->should_prune_fn)(ooid->hash, noid->hash, email, timestamp, tz,
                                   message, policy_cb)) {
                if (!cb->newlog)
                        printf("would prune %s", message);
@@ -3946,9 +3959,9 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
        } else {
                if (cb->newlog) {
                        fprintf(cb->newlog, "%s %s %s %lu %+05d\t%s",
-                               sha1_to_hex(osha1), sha1_to_hex(nsha1),
+                               oid_to_hex(ooid), oid_to_hex(noid),
                                email, timestamp, tz, message);
-                       hashcpy(cb->last_kept_sha1, nsha1);
+                       oidcpy(&cb->last_kept_oid, noid);
                }
                if (cb->flags & EXPIRE_REFLOGS_VERBOSE)
                        printf("keep %s", message);
@@ -4035,14 +4048,14 @@ static int files_reflog_expire(struct ref_store *ref_store,
                 */
                int update = (flags & EXPIRE_REFLOGS_UPDATE_REF) &&
                        !(type & REF_ISSYMREF) &&
-                       !is_null_sha1(cb.last_kept_sha1);
+                       !is_null_oid(&cb.last_kept_oid);
 
                if (close_lock_file(&reflog_lock)) {
                        status |= error("couldn't write %s: %s", log_file,
                                        strerror(errno));
                } else if (update &&
                           (write_in_full(get_lock_file_fd(lock->lk),
-                               sha1_to_hex(cb.last_kept_sha1), 40) != 40 ||
+                               oid_to_hex(&cb.last_kept_oid), GIT_SHA1_HEXSZ) != GIT_SHA1_HEXSZ ||
                            write_str_in_full(get_lock_file_fd(lock->lk), "\n") != 1 ||
                            close_ref(lock) < 0)) {
                        status |= error("couldn't write %s",