Add callback data to for_each_ref() family.
[gitweb.git] / refs.c
diff --git a/refs.c b/refs.c
index 50c25d3d28b099b9fef9d47cf25e45eaf74da5f0..85564f0dc70ffd298daf3a9f2bb84801b6564911 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -28,6 +28,8 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
        if (!isspace(line[40]))
                return NULL;
        line += 41;
+       if (isspace(*line))
+               return NULL;
        if (line[len] != '\n')
                return NULL;
        line[len] = 0;
@@ -168,6 +170,14 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading)
                 * reading.
                 */
                if (lstat(path, &st) < 0) {
+                       struct ref_list *list = get_packed_refs();
+                       while (list) {
+                               if (!strcmp(ref, list->name)) {
+                                       hashcpy(sha1, list->sha1);
+                                       return ref;
+                               }
+                               list = list->next;
+                       }
                        if (reading || errno != ENOENT)
                                return NULL;
                        hashclr(sha1);
@@ -265,7 +275,7 @@ int read_ref(const char *ref, unsigned char *sha1)
        return -1;
 }
 
-static int do_for_each_ref(const char *base, int (*fn)(const char *path, const unsigned char *sha1), int trim)
+static int do_for_each_ref(const char *base, each_ref_fn fn, int trim, void *cb_data)
 {
        int retval;
        struct ref_list *packed = get_packed_refs();
@@ -293,7 +303,7 @@ static int do_for_each_ref(const char *base, int (*fn)(const char *path, const u
                        error("%s does not point to a valid object!", entry->name);
                        continue;
                }
-               retval = fn(entry->name + trim, entry->sha1);
+               retval = fn(entry->name + trim, entry->sha1, cb_data);
                if (retval)
                        return retval;
        }
@@ -301,7 +311,7 @@ static int do_for_each_ref(const char *base, int (*fn)(const char *path, const u
        packed = packed ? packed : loose;
        while (packed) {
                if (!strncmp(base, packed->name, trim)) {
-                       retval = fn(packed->name + trim, packed->sha1);
+                       retval = fn(packed->name + trim, packed->sha1, cb_data);
                        if (retval)
                                return retval;
                }
@@ -310,34 +320,39 @@ static int do_for_each_ref(const char *base, int (*fn)(const char *path, const u
        return 0;
 }
 
-int head_ref(int (*fn)(const char *path, const unsigned char *sha1))
+int head_ref(each_ref_fn fn, void *cb_data)
 {
        unsigned char sha1[20];
        if (!read_ref("HEAD", sha1))
-               return fn("HEAD", sha1);
+               return fn("HEAD", sha1, cb_data);
        return 0;
 }
 
-int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1))
+int for_each_ref(each_ref_fn fn, void *cb_data)
 {
-       return do_for_each_ref("refs/", fn, 0);
+       return do_for_each_ref("refs/", fn, 0, cb_data);
 }
 
-int for_each_tag_ref(int (*fn)(const char *path, const unsigned char *sha1))
+int for_each_tag_ref(each_ref_fn fn, void *cb_data)
 {
-       return do_for_each_ref("refs/tags/", fn, 10);
+       return do_for_each_ref("refs/tags/", fn, 10, cb_data);
 }
 
-int for_each_branch_ref(int (*fn)(const char *path, const unsigned char *sha1))
+int for_each_branch_ref(each_ref_fn fn, void *cb_data)
 {
-       return do_for_each_ref("refs/heads/", fn, 11);
+       return do_for_each_ref("refs/heads/", fn, 11, cb_data);
 }
 
-int for_each_remote_ref(int (*fn)(const char *path, const unsigned char *sha1))
+int for_each_remote_ref(each_ref_fn fn, void *cb_data)
 {
-       return do_for_each_ref("refs/remotes/", fn, 13);
+       return do_for_each_ref("refs/remotes/", fn, 13, cb_data);
 }
 
+/* NEEDSWORK: This is only used by ssh-upload and it should go; the
+ * caller should do resolve_ref or read_ref like everybody else.  Or
+ * maybe everybody else should use get_ref_sha1() instead of doing
+ * read_ref().
+ */
 int get_ref_sha1(const char *ref, unsigned char *sha1)
 {
        if (check_ref_format(ref))
@@ -400,22 +415,13 @@ int check_ref_format(const char *ref)
 static struct ref_lock *verify_lock(struct ref_lock *lock,
        const unsigned char *old_sha1, int mustexist)
 {
-       char buf[40];
-       int nr, fd = open(lock->ref_file, O_RDONLY);
-       if (fd < 0 && (mustexist || errno != ENOENT)) {
-               error("Can't verify ref %s", lock->ref_file);
-               unlock_ref(lock);
-               return NULL;
-       }
-       nr = read(fd, buf, 40);
-       close(fd);
-       if (nr != 40 || get_sha1_hex(buf, lock->old_sha1) < 0) {
-               error("Can't verify ref %s", lock->ref_file);
+       if (!resolve_ref(lock->ref_name, lock->old_sha1, mustexist)) {
+               error("Can't verify ref %s", lock->ref_name);
                unlock_ref(lock);
                return NULL;
        }
        if (hashcmp(lock->old_sha1, old_sha1)) {
-               error("Ref %s is at %s but expected %s", lock->ref_file,
+               error("Ref %s is at %s but expected %s", lock->ref_name,
                        sha1_to_hex(lock->old_sha1), sha1_to_hex(old_sha1));
                unlock_ref(lock);
                return NULL;
@@ -427,6 +433,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref,
        int plen,
        const unsigned char *old_sha1, int mustexist)
 {
+       char *ref_file;
        const char *orig_ref = ref;
        struct ref_lock *lock;
        struct stat st;
@@ -445,13 +452,14 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref,
        }
        lock->lk = xcalloc(1, sizeof(struct lock_file));
 
-       lock->ref_file = xstrdup(git_path("%s", ref));
+       lock->ref_name = xstrdup(ref);
        lock->log_file = xstrdup(git_path("logs/%s", ref));
-       lock->force_write = lstat(lock->ref_file, &st) && errno == ENOENT;
+       ref_file = git_path(ref);
+       lock->force_write = lstat(ref_file, &st) && errno == ENOENT;
 
-       if (safe_create_leading_directories(lock->ref_file))
-               die("unable to create directory for %s", lock->ref_file);
-       lock->lock_fd = hold_lock_file_for_update(lock->lk, lock->ref_file, 1);
+       if (safe_create_leading_directories(ref_file))
+               die("unable to create directory for %s", ref_file);
+       lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, 1);
 
        return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock;
 }
@@ -459,10 +467,12 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref,
 struct ref_lock *lock_ref_sha1(const char *ref,
        const unsigned char *old_sha1, int mustexist)
 {
+       char refpath[PATH_MAX];
        if (check_ref_format(ref))
                return NULL;
-       return lock_ref_sha1_basic(mkpath("refs/%s", ref),
-               5 + strlen(ref), old_sha1, mustexist);
+       strcpy(refpath, mkpath("refs/%s", ref));
+       return lock_ref_sha1_basic(refpath, strlen(refpath),
+               old_sha1, mustexist);
 }
 
 struct ref_lock *lock_any_ref_for_update(const char *ref,
@@ -479,7 +489,7 @@ void unlock_ref(struct ref_lock *lock)
                if (lock->lk)
                        rollback_lock_file(lock->lk);
        }
-       free(lock->ref_file);
+       free(lock->ref_name);
        free(lock->log_file);
        free(lock);
 }
@@ -556,7 +566,7 @@ int write_ref_sha1(struct ref_lock *lock,
                return -1;
        }
        if (commit_lock_file(lock->lk)) {
-               error("Couldn't set %s", lock->ref_file);
+               error("Couldn't set %s", lock->ref_name);
                unlock_ref(lock);
                return -1;
        }