Prevent buffer overflows when path is too long
[gitweb.git] / remote.c
index a83dc90318d61a2fb94b2bf1572fbce3e8fd15f4..15e6e5efcf1643b084b697a7daf563d901a15c02 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -483,7 +483,7 @@ static void read_config(void)
        int flag;
        if (default_remote_name) /* did this already */
                return;
-       default_remote_name = xstrdup("origin");
+       default_remote_name = "origin";
        current_branch = NULL;
        head_ref = resolve_ref_unsafe("HEAD", sha1, 0, &flag);
        if (head_ref && (flag & REF_ISSYMREF) &&
@@ -745,35 +745,66 @@ int for_each_remote(each_remote_fn fn, void *priv)
        return result;
 }
 
-void ref_remove_duplicates(struct ref *ref_map)
+static void handle_duplicate(struct ref *ref1, struct ref *ref2)
+{
+       if (strcmp(ref1->name, ref2->name)) {
+               if (ref1->fetch_head_status != FETCH_HEAD_IGNORE &&
+                   ref2->fetch_head_status != FETCH_HEAD_IGNORE) {
+                       die(_("Cannot fetch both %s and %s to %s"),
+                           ref1->name, ref2->name, ref2->peer_ref->name);
+               } else if (ref1->fetch_head_status != FETCH_HEAD_IGNORE &&
+                          ref2->fetch_head_status == FETCH_HEAD_IGNORE) {
+                       warning(_("%s usually tracks %s, not %s"),
+                               ref2->peer_ref->name, ref2->name, ref1->name);
+               } else if (ref1->fetch_head_status == FETCH_HEAD_IGNORE &&
+                          ref2->fetch_head_status == FETCH_HEAD_IGNORE) {
+                       die(_("%s tracks both %s and %s"),
+                           ref2->peer_ref->name, ref1->name, ref2->name);
+               } else {
+                       /*
+                        * This last possibility doesn't occur because
+                        * FETCH_HEAD_IGNORE entries always appear at
+                        * the end of the list.
+                        */
+                       die(_("Internal error"));
+               }
+       }
+       free(ref2->peer_ref);
+       free(ref2);
+}
+
+struct ref *ref_remove_duplicates(struct ref *ref_map)
 {
        struct string_list refs = STRING_LIST_INIT_NODUP;
-       struct string_list_item *item = NULL;
-       struct ref *prev = NULL, *next = NULL;
-       for (; ref_map; prev = ref_map, ref_map = next) {
-               next = ref_map->next;
-               if (!ref_map->peer_ref)
-                       continue;
+       struct ref *retval = NULL;
+       struct ref **p = &retval;
 
-               item = string_list_lookup(&refs, ref_map->peer_ref->name);
-               if (item) {
-                       if (strcmp(((struct ref *)item->util)->name,
-                                  ref_map->name))
-                               die("%s tracks both %s and %s",
-                                   ref_map->peer_ref->name,
-                                   ((struct ref *)item->util)->name,
-                                   ref_map->name);
-                       prev->next = ref_map->next;
-                       free(ref_map->peer_ref);
-                       free(ref_map);
-                       ref_map = prev; /* skip this; we freed it */
-                       continue;
-               }
+       while (ref_map) {
+               struct ref *ref = ref_map;
+
+               ref_map = ref_map->next;
+               ref->next = NULL;
+
+               if (!ref->peer_ref) {
+                       *p = ref;
+                       p = &ref->next;
+               } else {
+                       struct string_list_item *item =
+                               string_list_insert(&refs, ref->peer_ref->name);
 
-               item = string_list_insert(&refs, ref_map->peer_ref->name);
-               item->util = ref_map;
+                       if (item->util) {
+                               /* Entry already existed */
+                               handle_duplicate((struct ref *)item->util, ref);
+                       } else {
+                               *p = ref;
+                               p = &ref->next;
+                               item->util = ref;
+                       }
+               }
        }
+
        string_list_clear(&refs, 0);
+       return retval;
 }
 
 int remote_has_url(struct remote *remote, const char *url)
@@ -825,6 +856,8 @@ static int query_refspecs(struct refspec *refs, int ref_count, struct refspec *q
 {
        int i;
        int find_src = !query->src;
+       const char *needle = find_src ? query->dst : query->src;
+       char **result = find_src ? &query->src : &query->dst;
 
        if (find_src && !query->dst)
                return error("query_refspecs: need either src or dst");
@@ -833,8 +866,6 @@ static int query_refspecs(struct refspec *refs, int ref_count, struct refspec *q
                struct refspec *refspec = &refs[i];
                const char *key = find_src ? refspec->dst : refspec->src;
                const char *value = find_src ? refspec->src : refspec->dst;
-               const char *needle = find_src ? query->dst : query->src;
-               char **result = find_src ? &query->src : &query->dst;
 
                if (!refspec->dst)
                        continue;