Code

Fix an enum assignment issue spotted by Sun Studio
[git.git] / refs.c
diff --git a/refs.c b/refs.c
index ea058c1c776c6aa22cabe00658e35c2b10a51219..6f436f1cb05e62c6afda086f5e410a268cf8bb52 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -53,28 +53,30 @@ 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)
+static struct ref_entry *create_ref_entry(const char *refname,
+                                         const unsigned char *sha1, int flag,
+                                         int check_name)
 {
        int len;
-       struct ref_entry *entry;
+       struct ref_entry *ref;
 
-       /* Allocate it and add it in.. */
-       len = strlen(refname) + 1;
-       entry = xmalloc(sizeof(struct ref_entry) + len);
-       hashcpy(entry->sha1, sha1);
-       hashclr(entry->peeled);
        if (check_name &&
            check_refname_format(refname, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
                die("Reference has invalid format: '%s'", refname);
-       memcpy(entry->name, refname, len);
-       entry->flag = flag;
-       if (new_entry)
-               *new_entry = entry;
+       len = strlen(refname) + 1;
+       ref = xmalloc(sizeof(struct ref_entry) + len);
+       hashcpy(ref->sha1, sha1);
+       hashclr(ref->peeled);
+       memcpy(ref->name, refname, len);
+       ref->flag = flag;
+       return ref;
+}
+
+/* Add a ref_entry to the end of the ref_array (unsorted). */
+static void add_ref(struct ref_array *refs, struct ref_entry *ref)
+{
        ALLOC_GROW(refs->refs, refs->nr + 1, refs->alloc);
-       refs->refs[refs->nr++] = entry;
+       refs->refs[refs->nr++] = ref;
 }
 
 static int ref_entry_cmp(const void *a, const void *b)
@@ -255,7 +257,8 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
 
                refname = parse_ref_line(refline, sha1);
                if (refname) {
-                       add_ref(refname, sha1, flag, 1, array, &last);
+                       last = create_ref_entry(refname, sha1, flag, 1);
+                       add_ref(array, last);
                        continue;
                }
                if (last &&
@@ -270,7 +273,7 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
 
 void add_extra_ref(const char *refname, const unsigned char *sha1, int flag)
 {
-       add_ref(refname, sha1, flag, 0, &extra_refs, NULL);
+       add_ref(&extra_refs, create_ref_entry(refname, sha1, flag, 0));
 }
 
 void clear_extra_refs(void)
@@ -278,16 +281,14 @@ void clear_extra_refs(void)
        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");
@@ -300,14 +301,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);
 
@@ -338,19 +339,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;
                                }
@@ -358,7 +359,7 @@ static void get_ref_dir(const char *submodule, const char *base,
                                hashclr(sha1);
                                flag |= REF_ISBROKEN;
                        }
-                       add_ref(refname, sha1, flag, 1, array, NULL);
+                       add_ref(array, create_ref_entry(refname, sha1, flag, 1));
                }
                free(refname);
                closedir(dir);
@@ -381,7 +382,7 @@ static int warn_if_dangling_symref(const char *refname, const unsigned char *sha
        if (!(flags & REF_ISSYMREF))
                return 0;
 
-       resolves_to = resolve_ref(refname, junk, 0, NULL);
+       resolves_to = resolve_ref_unsafe(refname, junk, 0, NULL);
        if (!resolves_to || strcmp(resolves_to, d->refname))
                return 0;
 
@@ -399,12 +400,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;
        }
@@ -417,42 +416,39 @@ static struct ref_array *get_loose_refs(const char *submodule)
 
 /*
  * Called by resolve_gitlink_ref_recursive() after it failed to read
- * from "name", which is "module/.git/<refname>". Find <refname> in
- * the packed-refs file for the submodule.
+ * from the loose refs in ref_cache refs. Find <refname> in the
+ * packed-refs file for the submodule.
  */
-static int resolve_gitlink_packed_ref(char *name, int pathlen,
+static int resolve_gitlink_packed_ref(struct ref_cache *refs,
                                      const char *refname, unsigned char *sha1)
 {
-       int retval = -1;
        struct ref_entry *ref;
-       struct ref_array *array;
+       struct ref_array *array = get_packed_refs(refs);
 
-       /* being defensive: resolve_gitlink_ref() did this for us */
-       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);
        ref = search_ref_array(array, refname);
-       if (ref != NULL) {
-               memcpy(sha1, ref->sha1, 20);
-               retval = 0;
-       }
-       return retval;
+       if (ref == NULL)
+               return -1;
+
+       memcpy(sha1, ref->sha1, 20);
+       return 0;
 }
 
-static int resolve_gitlink_ref_recursive(char *name, int pathlen,
+static int resolve_gitlink_ref_recursive(struct ref_cache *refs,
                                         const char *refname, unsigned char *sha1,
                                         int recursion)
 {
-       int fd, len = strlen(refname);
+       int fd, len;
        char buffer[128], *p;
+       char *path;
 
-       if (recursion > MAXDEPTH || len > MAXREFLEN)
+       if (recursion > MAXDEPTH || strlen(refname) > MAXREFLEN)
                return -1;
-       memcpy(name + pathlen, refname, len+1);
-       fd = open(name, O_RDONLY);
+       path = *refs->name
+               ? git_path_submodule(refs->name, "%s", refname)
+               : git_path("%s", refname);
+       fd = open(path, O_RDONLY);
        if (fd < 0)
-               return resolve_gitlink_packed_ref(name, pathlen, refname, sha1);
+               return resolve_gitlink_packed_ref(refs, refname, sha1);
 
        len = read(fd, buffer, sizeof(buffer)-1);
        close(fd);
@@ -473,35 +469,24 @@ static int resolve_gitlink_ref_recursive(char *name, int pathlen,
        while (isspace(*p))
                p++;
 
-       return resolve_gitlink_ref_recursive(name, pathlen, p, sha1, recursion+1);
+       return resolve_gitlink_ref_recursive(refs, p, sha1, recursion+1);
 }
 
 int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)
 {
        int len = strlen(path), retval;
-       char *gitdir;
-       const char *tmp;
+       char *submodule;
+       struct ref_cache *refs;
 
        while (len && path[len-1] == '/')
                len--;
        if (!len)
                return -1;
-       gitdir = xmalloc(len + MAXREFLEN + 8);
-       memcpy(gitdir, path, len);
-       memcpy(gitdir + len, "/.git", 6);
-       len += 5;
-
-       tmp = read_gitfile(gitdir);
-       if (tmp) {
-               free(gitdir);
-               len = strlen(tmp);
-               gitdir = xmalloc(len + MAXREFLEN + 3);
-               memcpy(gitdir, tmp, len);
-       }
-       gitdir[len] = '/';
-       gitdir[++len] = '\0';
-       retval = resolve_gitlink_ref_recursive(gitdir, len, refname, sha1, 0);
-       free(gitdir);
+       submodule = xstrndup(path, len);
+       refs = get_ref_cache(submodule);
+       free(submodule);
+
+       retval = resolve_gitlink_ref_recursive(refs, refname, sha1, 0);
        return retval;
 }
 
@@ -511,7 +496,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);
@@ -520,7 +505,7 @@ static int get_packed_ref(const char *refname, unsigned char *sha1)
        return -1;
 }
 
-const char *resolve_ref(const char *refname, unsigned char *sha1, int reading, int *flag)
+const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int reading, int *flag)
 {
        int depth = MAXDEPTH;
        ssize_t len;
@@ -628,6 +613,12 @@ const char *resolve_ref(const char *refname, unsigned char *sha1, int reading, i
        return refname;
 }
 
+char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag)
+{
+       const char *ret = resolve_ref_unsafe(ref, sha1, reading, flag);
+       return ret ? xstrdup(ret) : NULL;
+}
+
 /* The argument to filter_refs */
 struct ref_filter {
        const char *pattern;
@@ -637,7 +628,7 @@ struct ref_filter {
 
 int read_ref_full(const char *refname, unsigned char *sha1, int reading, int *flags)
 {
-       if (resolve_ref(refname, sha1, reading, flags))
+       if (resolve_ref_unsafe(refname, sha1, reading, flags))
                return 0;
        return -1;
 }
@@ -695,7 +686,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) {
@@ -720,8 +711,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;
 
@@ -1140,7 +1132,7 @@ int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
 
                this_result = refs_found ? sha1_from_ref : sha1;
                mksnpath(fullref, sizeof(fullref), *p, len, str);
-               r = resolve_ref(fullref, this_result, 1, &flag);
+               r = resolve_ref_unsafe(fullref, this_result, 1, &flag);
                if (r) {
                        if (!refs_found++)
                                *ref = xstrdup(r);
@@ -1170,7 +1162,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
                const char *ref, *it;
 
                mksnpath(path, sizeof(path), *p, len, str);
-               ref = resolve_ref(path, hash, 1, NULL);
+               ref = resolve_ref_unsafe(path, hash, 1, NULL);
                if (!ref)
                        continue;
                if (!stat(git_path("logs/%s", path), &st) &&
@@ -1208,7 +1200,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
        lock = xcalloc(1, sizeof(struct ref_lock));
        lock->lock_fd = -1;
 
-       refname = resolve_ref(refname, lock->old_sha1, mustexist, &type);
+       refname = resolve_ref_unsafe(refname, lock->old_sha1, mustexist, &type);
        if (!refname && errno == EISDIR) {
                /* we are trying to lock foo but we used to
                 * have foo/bar which now does not exist;
@@ -1221,7 +1213,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
                        error("there are still refs under '%s'", orig_refname);
                        goto error_return;
                }
-               refname = resolve_ref(orig_refname, lock->old_sha1, mustexist, &type);
+               refname = resolve_ref_unsafe(orig_refname, lock->old_sha1, mustexist, &type);
        }
        if (type_p)
            *type_p = type;
@@ -1238,7 +1230,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))) {
+            !is_refname_available(refname, NULL, get_packed_refs(get_ref_cache(NULL)))) {
                last_errno = ENOTDIR;
                goto error_return;
        }
@@ -1295,12 +1287,10 @@ static struct lock_file packlock;
 static int repack_without_ref(const char *refname)
 {
        struct ref_array *packed;
-       struct ref_entry *ref;
        int fd, i;
 
-       packed = get_packed_refs(NULL);
-       ref = search_ref_array(packed, refname);
-       if (ref == NULL)
+       packed = get_packed_refs(get_ref_cache(NULL));
+       if (search_ref_array(packed, refname) == NULL)
                return 0;
        fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
        if (fd < 0) {
@@ -1311,8 +1301,7 @@ static int repack_without_ref(const char *refname)
        for (i = 0; i < packed->nr; i++) {
                char line[PATH_MAX + 100];
                int len;
-
-               ref = packed->refs[i];
+               struct ref_entry *ref = packed->refs[i];
 
                if (!strcmp(refname, ref->name))
                        continue;
@@ -1381,21 +1370,22 @@ 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);
 
-       symref = resolve_ref(oldrefname, orig_sha1, 1, &flag);
+       symref = resolve_ref_unsafe(oldrefname, orig_sha1, 1, &flag);
        if (flag & REF_ISSYMREF)
                return error("refname %s is a symbolic ref, renaming it is not supported",
                        oldrefname);
        if (!symref)
                return error("refname %s not found", oldrefname);
 
-       if (!is_refname_available(newrefname, oldrefname, get_packed_refs(NULL)))
+       if (!is_refname_available(newrefname, oldrefname, get_packed_refs(refs)))
                return 1;
 
-       if (!is_refname_available(newrefname, oldrefname, get_loose_refs(NULL)))
+       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)))
@@ -1674,7 +1664,7 @@ int write_ref_sha1(struct ref_lock *lock,
                unsigned char head_sha1[20];
                int head_flag;
                const char *head_ref;
-               head_ref = resolve_ref("HEAD", head_sha1, 1, &head_flag);
+               head_ref = resolve_ref_unsafe("HEAD", head_sha1, 1, &head_flag);
                if (head_ref && (head_flag & REF_ISSYMREF) &&
                    !strcmp(head_ref, lock->ref_name))
                        log_ref_write("HEAD", lock->old_sha1, sha1, logmsg);
@@ -2013,7 +2003,7 @@ int update_ref(const char *action, const char *refname,
 int ref_exists(const char *refname)
 {
        unsigned char sha1[20];
-       return !!resolve_ref(refname, sha1, 1, NULL);
+       return !!resolve_ref_unsafe(refname, sha1, 1, NULL);
 }
 
 struct ref *find_ref_by_name(const struct ref *list, const char *name)