get_ref_dir(): change signature
[gitweb.git] / refs.c
diff --git a/refs.c b/refs.c
index 9f7a5ec46b8bcfd6fc62b67894f3ad3a7e0a8e45..91ec3954b78d59000cad99fdeea2761d1f0831b4 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -20,6 +20,11 @@ struct ref_array {
        struct ref_entry **refs;
 };
 
+/*
+ * Parse one line from a packed-refs file.  Write the SHA1 to sha1.
+ * Return a pointer to the refname within the line (null-terminated),
+ * or NULL if there was a problem.
+ */
 static const char *parse_ref_line(char *line, unsigned char *sha1)
 {
        /*
@@ -48,6 +53,7 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
        return line;
 }
 
+/* Add a ref_entry to the end of the ref_array (unsorted). */
 static void add_ref(const char *refname, const unsigned char *sha1,
                    int flag, int check_name, struct ref_array *refs,
                    struct ref_entry **new_entry)
@@ -78,9 +84,28 @@ static int ref_entry_cmp(const void *a, const void *b)
        return strcmp(one->name, two->name);
 }
 
+/*
+ * Emit a warning and return true iff ref1 and ref2 have the same name
+ * and the same sha1.  Die if they have the same name but different
+ * sha1s.
+ */
+static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2)
+{
+       if (!strcmp(ref1->name, ref2->name)) {
+               /* Duplicate name; make sure that the SHA1s match: */
+               if (hashcmp(ref1->sha1, ref2->sha1))
+                       die("Duplicated ref, and SHA1s don't match: %s",
+                           ref1->name);
+               warning("Duplicated ref: %s", ref1->name);
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
 static void sort_ref_array(struct ref_array *array)
 {
-       int i = 0, j = 1;
+       int i, j;
 
        /* Nothing to sort unless there are at least two entries */
        if (array->nr < 2)
@@ -89,19 +114,13 @@ static void sort_ref_array(struct ref_array *array)
        qsort(array->refs, array->nr, sizeof(*array->refs), ref_entry_cmp);
 
        /* Remove any duplicates from the ref_array */
-       for (; j < array->nr; j++) {
-               struct ref_entry *a = array->refs[i];
-               struct ref_entry *b = array->refs[j];
-               if (!strcmp(a->name, b->name)) {
-                       if (hashcmp(a->sha1, b->sha1))
-                               die("Duplicated ref, and SHA1s don't match: %s",
-                                   a->name);
-                       warning("Duplicated ref: %s", a->name);
-                       free(b);
+       i = 0;
+       for (j = 1; j < array->nr; j++) {
+               if (is_dup_ref(array->refs[i], array->refs[j])) {
+                       free(array->refs[j]);
                        continue;
                }
-               i++;
-               array->refs[i] = array->refs[j];
+               array->refs[++i] = array->refs[j];
        }
        array->nr = i + 1;
 }
@@ -149,7 +168,7 @@ static struct ref_entry *current_ref;
 
 static struct ref_array extra_refs;
 
-static void free_ref_array(struct ref_array *array)
+static void clear_ref_array(struct ref_array *array)
 {
        int i;
        for (i = 0; i < array->nr; i++)
@@ -162,14 +181,14 @@ static void free_ref_array(struct ref_array *array)
 static void clear_packed_ref_cache(struct ref_cache *refs)
 {
        if (refs->did_packed)
-               free_ref_array(&refs->packed);
+               clear_ref_array(&refs->packed);
        refs->did_packed = 0;
 }
 
 static void clear_loose_ref_cache(struct ref_cache *refs)
 {
        if (refs->did_loose)
-               free_ref_array(&refs->loose);
+               clear_ref_array(&refs->loose);
        refs->did_loose = 0;
 }
 
@@ -256,19 +275,17 @@ void add_extra_ref(const char *refname, const unsigned char *sha1, int flag)
 
 void clear_extra_refs(void)
 {
-       free_ref_array(&extra_refs);
+       clear_ref_array(&extra_refs);
 }
 
-static struct ref_array *get_packed_refs(const char *submodule)
+static struct ref_array *get_packed_refs(struct ref_cache *refs)
 {
-       struct ref_cache *refs = get_ref_cache(submodule);
-
        if (!refs->did_packed) {
                const char *packed_refs_file;
                FILE *f;
 
-               if (submodule)
-                       packed_refs_file = git_path_submodule(submodule, "packed-refs");
+               if (*refs->name)
+                       packed_refs_file = git_path_submodule(refs->name, "packed-refs");
                else
                        packed_refs_file = git_path("packed-refs");
                f = fopen(packed_refs_file, "r");
@@ -281,14 +298,14 @@ static struct ref_array *get_packed_refs(const char *submodule)
        return &refs->packed;
 }
 
-static void get_ref_dir(const char *submodule, const char *base,
+static void get_ref_dir(struct ref_cache *refs, const char *base,
                        struct ref_array *array)
 {
        DIR *dir;
        const char *path;
 
-       if (submodule)
-               path = git_path_submodule(submodule, "%s", base);
+       if (*refs->name)
+               path = git_path_submodule(refs->name, "%s", base);
        else
                path = git_path("%s", base);
 
@@ -319,19 +336,19 @@ static void get_ref_dir(const char *submodule, const char *base,
                        if (has_extension(de->d_name, ".lock"))
                                continue;
                        memcpy(refname + baselen, de->d_name, namelen+1);
-                       refdir = submodule
-                               ? git_path_submodule(submodule, "%s", refname)
+                       refdir = *refs->name
+                               ? git_path_submodule(refs->name, "%s", refname)
                                : git_path("%s", refname);
                        if (stat(refdir, &st) < 0)
                                continue;
                        if (S_ISDIR(st.st_mode)) {
-                               get_ref_dir(submodule, refname, array);
+                               get_ref_dir(refs, refname, array);
                                continue;
                        }
-                       if (submodule) {
+                       if (*refs->name) {
                                hashclr(sha1);
                                flag = 0;
-                               if (resolve_gitlink_ref(submodule, refname, sha1) < 0) {
+                               if (resolve_gitlink_ref(refs->name, refname, sha1) < 0) {
                                        hashclr(sha1);
                                        flag |= REF_ISBROKEN;
                                }
@@ -380,12 +397,10 @@ void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)
        for_each_rawref(warn_if_dangling_symref, &data);
 }
 
-static struct ref_array *get_loose_refs(const char *submodule)
+static struct ref_array *get_loose_refs(struct ref_cache *refs)
 {
-       struct ref_cache *refs = get_ref_cache(submodule);
-
        if (!refs->did_loose) {
-               get_ref_dir(submodule, "refs", &refs->loose);
+               get_ref_dir(refs, "refs", &refs->loose);
                sort_ref_array(&refs->loose);
                refs->did_loose = 1;
        }
@@ -412,7 +427,7 @@ static int resolve_gitlink_packed_ref(char *name, int pathlen,
        if (pathlen < 6 || memcmp(name + pathlen - 6, "/.git/", 6))
                die("Oops");
        name[pathlen - 6] = '\0'; /* make it path to the submodule */
-       array = get_packed_refs(name);
+       array = get_packed_refs(get_ref_cache(name));
        ref = search_ref_array(array, refname);
        if (ref != NULL) {
                memcpy(sha1, ref->sha1, 20);
@@ -492,7 +507,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh
  */
 static int get_packed_ref(const char *refname, unsigned char *sha1)
 {
-       struct ref_array *packed = get_packed_refs(NULL);
+       struct ref_array *packed = get_packed_refs(get_ref_cache(NULL));
        struct ref_entry *entry = search_ref_array(packed, refname);
        if (entry) {
                hashcpy(sha1, entry->sha1);
@@ -676,7 +691,7 @@ int peel_ref(const char *refname, unsigned char *sha1)
                return -1;
 
        if ((flag & REF_ISPACKED)) {
-               struct ref_array *array = get_packed_refs(NULL);
+               struct ref_array *array = get_packed_refs(get_ref_cache(NULL));
                struct ref_entry *r = search_ref_array(array, refname);
 
                if (r != NULL && r->flag & REF_KNOWS_PEELED) {
@@ -701,8 +716,9 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn
                           int trim, int flags, void *cb_data)
 {
        int retval = 0, i, p = 0, l = 0;
-       struct ref_array *packed = get_packed_refs(submodule);
-       struct ref_array *loose = get_loose_refs(submodule);
+       struct ref_cache *refs = get_ref_cache(submodule);
+       struct ref_array *packed = get_packed_refs(refs);
+       struct ref_array *loose = get_loose_refs(refs);
 
        struct ref_array *extra = &extra_refs;
 
@@ -1057,8 +1073,15 @@ static int remove_empty_directories(const char *file)
        return result;
 }
 
+/*
+ * Return true iff a reference named refname could be created without
+ * conflicting with the name of an existing reference.  If oldrefname
+ * is non-NULL, ignore potential conflicts with oldrefname (e.g.,
+ * because oldrefname is scheduled for deletion in the same
+ * operation).
+ */
 static int is_refname_available(const char *refname, const char *oldrefname,
-                               struct ref_array *array, int quiet)
+                               struct ref_array *array)
 {
        int i, namlen = strlen(refname); /* e.g. 'foo/bar' */
        for (i = 0; i < array->nr; i++ ) {
@@ -1070,9 +1093,8 @@ static int is_refname_available(const char *refname, const char *oldrefname,
                        const char *lead = (namlen < len) ? entry->name : refname;
                        if (!strncmp(refname, entry->name, cmplen) &&
                            lead[cmplen] == '/') {
-                               if (!quiet)
-                                       error("'%s' exists; cannot create '%s'",
-                                             entry->name, refname);
+                               error("'%s' exists; cannot create '%s'",
+                                     entry->name, refname);
                                return 0;
                        }
                }
@@ -1213,7 +1235,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
         * name is a proper prefix of our refname.
         */
        if (missing &&
-            !is_refname_available(refname, NULL, get_packed_refs(NULL), 0)) {
+            !is_refname_available(refname, NULL, get_packed_refs(get_ref_cache(NULL)))) {
                last_errno = ENOTDIR;
                goto error_return;
        }
@@ -1273,7 +1295,7 @@ static int repack_without_ref(const char *refname)
        struct ref_entry *ref;
        int fd, i;
 
-       packed = get_packed_refs(NULL);
+       packed = get_packed_refs(get_ref_cache(NULL));
        ref = search_ref_array(packed, refname);
        if (ref == NULL)
                return 0;
@@ -1356,6 +1378,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
        struct stat loginfo;
        int log = !lstat(git_path("logs/%s", oldrefname), &loginfo);
        const char *symref = NULL;
+       struct ref_cache *refs = get_ref_cache(NULL);
 
        if (log && S_ISLNK(loginfo.st_mode))
                return error("reflog for %s is a symlink", oldrefname);
@@ -1367,10 +1390,10 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
        if (!symref)
                return error("refname %s not found", oldrefname);
 
-       if (!is_refname_available(newrefname, oldrefname, get_packed_refs(NULL), 0))
+       if (!is_refname_available(newrefname, oldrefname, get_packed_refs(refs)))
                return 1;
 
-       if (!is_refname_available(newrefname, oldrefname, get_loose_refs(NULL), 0))
+       if (!is_refname_available(newrefname, oldrefname, get_loose_refs(refs)))
                return 1;
 
        if (log && rename(git_path("logs/%s", oldrefname), git_path(TMP_RENAMED_LOG)))