Merge branch 'sb/plug-leaks'
authorJunio C Hamano <gitster@pobox.com>
Tue, 9 Sep 2014 19:54:01 +0000 (12:54 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 9 Sep 2014 19:54:02 +0000 (12:54 -0700)
* sb/plug-leaks:
clone.c: don't leak memory in cmd_clone
remote.c: don't leak the base branch name in format_tracking_info

1  2 
builtin/clone.c
remote.c
diff --combined builtin/clone.c
index bbd169ceb49b2e09197e469aeb572e9aa54d4b85,9129eb799fe8e4b8538e04da6be0811030984a0d..dd4092b0509eb9f284118c001d8451a633f9ef7c
@@@ -521,7 -521,7 +521,7 @@@ static void write_followtags(const stru
                if (!has_sha1_file(ref->old_sha1))
                        continue;
                update_ref(msg, ref->name, ref->old_sha1,
 -                         NULL, 0, DIE_ON_ERR);
 +                         NULL, 0, UPDATE_REFS_DIE_ON_ERR);
        }
  }
  
@@@ -584,20 -584,19 +584,20 @@@ static void update_remote_refs(const st
  static void update_head(const struct ref *our, const struct ref *remote,
                        const char *msg)
  {
 -      if (our && starts_with(our->name, "refs/heads/")) {
 +      const char *head;
 +      if (our && skip_prefix(our->name, "refs/heads/", &head)) {
                /* Local default branch link */
                create_symref("HEAD", our->name, NULL);
                if (!option_bare) {
 -                      const char *head = skip_prefix(our->name, "refs/heads/");
 -                      update_ref(msg, "HEAD", our->old_sha1, NULL, 0, DIE_ON_ERR);
 +                      update_ref(msg, "HEAD", our->old_sha1, NULL, 0,
 +                                 UPDATE_REFS_DIE_ON_ERR);
                        install_branch_config(0, head, option_origin, our->name);
                }
        } else if (our) {
                struct commit *c = lookup_commit_reference(our->old_sha1);
                /* --branch specifies a non-branch (i.e. tags), detach HEAD */
                update_ref(msg, "HEAD", c->object.sha1,
 -                         NULL, REF_NODEREF, DIE_ON_ERR);
 +                         NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
        } else if (remote) {
                /*
                 * We know remote HEAD points to a non-branch, or
                 * Detach HEAD in all these cases.
                 */
                update_ref(msg, "HEAD", remote->old_sha1,
 -                         NULL, REF_NODEREF, DIE_ON_ERR);
 +                         NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
        }
  }
  
@@@ -617,7 -616,7 +617,7 @@@ static int checkout(void
        struct unpack_trees_options opts;
        struct tree *tree;
        struct tree_desc t;
 -      int err = 0, fd;
 +      int err = 0;
  
        if (option_no_checkout)
                return 0;
        setup_work_tree();
  
        lock_file = xcalloc(1, sizeof(struct lock_file));
 -      fd = hold_locked_index(lock_file, 1);
 +      hold_locked_index(lock_file, 1);
  
        memset(&opts, 0, sizeof opts);
        opts.update = 1;
        if (unpack_trees(1, &t, &opts) < 0)
                die(_("unable to checkout working tree"));
  
 -      if (write_cache(fd, active_cache, active_nr) ||
 -          commit_locked_index(lock_file))
 +      if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
  
        err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1),
@@@ -702,12 -702,9 +702,12 @@@ static void write_refspec_config(const 
                                        strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name,
                                                branch_top->buf, option_branch);
                        } else if (remote_head_points_at) {
 +                              const char *head = remote_head_points_at->name;
 +                              if (!skip_prefix(head, "refs/heads/", &head))
 +                                      die("BUG: remote HEAD points at non-head?");
 +
                                strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name,
 -                                              branch_top->buf,
 -                                              skip_prefix(remote_head_points_at->name, "refs/heads/"));
 +                                              branch_top->buf, head);
                        }
                        /*
                         * otherwise, the next "git fetch" will
@@@ -799,6 -796,18 +799,6 @@@ int cmd_clone(int argc, const char **ar
                die(_("repository '%s' does not exist"), repo_name);
        else
                repo = repo_name;
 -      is_local = option_local != 0 && path && !is_bundle;
 -      if (is_local) {
 -              if (option_depth)
 -                      warning(_("--depth is ignored in local clones; use file:// instead."));
 -              if (!access(mkpath("%s/shallow", path), F_OK)) {
 -                      if (option_local > 0)
 -                              warning(_("source repository is shallow, ignoring --local"));
 -                      is_local = 0;
 -              }
 -      }
 -      if (option_local > 0 && !is_local)
 -              warning(_("--local is ignored"));
  
        /* no need to be strict, transport_set_option() will validate it again */
        if (option_depth && atoi(option_depth) < 1)
  
        remote = remote_get(option_origin);
        transport = transport_get(remote, remote->url[0]);
 +      path = get_repo_path(remote->url[0], &is_bundle);
 +      is_local = option_local != 0 && path && !is_bundle;
 +      if (is_local) {
 +              if (option_depth)
 +                      warning(_("--depth is ignored in local clones; use file:// instead."));
 +              if (!access(mkpath("%s/shallow", path), F_OK)) {
 +                      if (option_local > 0)
 +                              warning(_("source repository is shallow, ignoring --local"));
 +                      is_local = 0;
 +              }
 +      }
 +      if (option_local > 0 && !is_local)
 +              warning(_("--local is ignored"));
        transport->cloning = 1;
  
        if (!transport->get_refs_list || (!is_local && !transport->fetch))
        strbuf_release(&key);
        strbuf_release(&value);
        junk_mode = JUNK_LEAVE_ALL;
+       free(refspec);
        return err;
  }
diff --combined remote.c
index 846cd1969c3b9d0316a5d3e44b0d401ec8d6f86e,a80518362dedd79bc13893b2ff4cc8ba695417a9..0e39b2442d90db07b2ad53069af2263b15472870
+++ b/remote.c
@@@ -42,7 -42,6 +42,7 @@@ struct rewrites 
  static struct remote **remotes;
  static int remotes_alloc;
  static int remotes_nr;
 +static struct hashmap remotes_hash;
  
  static struct branch **branches;
  static int branches_alloc;
@@@ -137,51 -136,26 +137,51 @@@ static void add_url_alias(struct remot
        add_pushurl_alias(remote, url);
  }
  
 +struct remotes_hash_key {
 +      const char *str;
 +      int len;
 +};
 +
 +static int remotes_hash_cmp(const struct remote *a, const struct remote *b, const struct remotes_hash_key *key)
 +{
 +      if (key)
 +              return strncmp(a->name, key->str, key->len) || a->name[key->len];
 +      else
 +              return strcmp(a->name, b->name);
 +}
 +
 +static inline void init_remotes_hash(void)
 +{
 +      if (!remotes_hash.cmpfn)
 +              hashmap_init(&remotes_hash, (hashmap_cmp_fn)remotes_hash_cmp, 0);
 +}
 +
  static struct remote *make_remote(const char *name, int len)
  {
 -      struct remote *ret;
 -      int i;
 +      struct remote *ret, *replaced;
 +      struct remotes_hash_key lookup;
 +      struct hashmap_entry lookup_entry;
  
 -      for (i = 0; i < remotes_nr; i++) {
 -              if (len ? (!strncmp(name, remotes[i]->name, len) &&
 -                         !remotes[i]->name[len]) :
 -                  !strcmp(name, remotes[i]->name))
 -                      return remotes[i];
 -      }
 +      if (!len)
 +              len = strlen(name);
 +
 +      init_remotes_hash();
 +      lookup.str = name;
 +      lookup.len = len;
 +      hashmap_entry_init(&lookup_entry, memhash(name, len));
 +
 +      if ((ret = hashmap_get(&remotes_hash, &lookup_entry, &lookup)) != NULL)
 +              return ret;
  
        ret = xcalloc(1, sizeof(struct remote));
        ret->prune = -1;  /* unspecified */
        ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);
        remotes[remotes_nr++] = ret;
 -      if (len)
 -              ret->name = xstrndup(name, len);
 -      else
 -              ret->name = xstrdup(name);
 +      ret->name = xstrndup(name, len);
 +
 +      hashmap_entry_init(ret, lookup_entry.hash);
 +      replaced = hashmap_put(&remotes_hash, ret);
 +      assert(replaced == NULL);  /* no previous entry overwritten */
        return ret;
  }
  
@@@ -196,6 -170,7 +196,6 @@@ static struct branch *make_branch(cons
  {
        struct branch *ret;
        int i;
 -      char *refname;
  
        for (i = 0; i < branches_nr; i++) {
                if (len ? (!strncmp(name, branches[i]->name, len) &&
                ret->name = xstrndup(name, len);
        else
                ret->name = xstrdup(name);
 -      refname = xmalloc(strlen(name) + strlen("refs/heads/") + 1);
 -      strcpy(refname, "refs/heads/");
 -      strcpy(refname + strlen("refs/heads/"), ret->name);
 -      ret->refname = refname;
 +      ret->refname = xstrfmt("refs/heads/%s", ret->name);
  
        return ret;
  }
@@@ -510,8 -488,9 +510,8 @@@ static void read_config(void
        current_branch = NULL;
        head_ref = resolve_ref_unsafe("HEAD", sha1, 0, &flag);
        if (head_ref && (flag & REF_ISSYMREF) &&
 -          starts_with(head_ref, "refs/heads/")) {
 -              current_branch =
 -                      make_branch(head_ref + strlen("refs/heads/"), 0);
 +          skip_prefix(head_ref, "refs/heads/", &head_ref)) {
 +              current_branch = make_branch(head_ref, 0);
        }
        git_config(handle_config, NULL);
        if (branch_pushremote_name) {
@@@ -743,16 -722,13 +743,16 @@@ struct remote *pushremote_get(const cha
  
  int remote_is_configured(const char *name)
  {
 -      int i;
 +      struct remotes_hash_key lookup;
 +      struct hashmap_entry lookup_entry;
        read_config();
  
 -      for (i = 0; i < remotes_nr; i++)
 -              if (!strcmp(name, remotes[i]->name))
 -                      return 1;
 -      return 0;
 +      init_remotes_hash();
 +      lookup.str = name;
 +      lookup.len = strlen(name);
 +      hashmap_entry_init(&lookup_entry, memhash(name, lookup.len));
 +
 +      return hashmap_get(&remotes_hash, &lookup_entry, &lookup) != NULL;
  }
  
  int for_each_remote(each_remote_fn fn, void *priv)
@@@ -1218,7 -1194,7 +1218,7 @@@ static int match_explicit(struct ref *s
        case 1:
                break;
        case 0:
 -              if (!memcmp(dst_value, "refs/", 5))
 +              if (starts_with(dst_value, "refs/"))
                        matched_dst = make_linked_ref(dst_value, dst_tail);
                else if (is_null_sha1(matched_src->new_sha1))
                        error("unable to delete '%s': remote ref does not exist",
@@@ -1949,7 -1925,7 +1949,7 @@@ int stat_tracking_info(struct branch *b
  int format_tracking_info(struct branch *branch, struct strbuf *sb)
  {
        int ours, theirs;
-       const char *base;
+       char *base;
        int upstream_is_gone = 0;
  
        switch (stat_tracking_info(branch, &ours, &theirs)) {
                break;
        }
  
-       base = branch->merge[0]->dst;
-       base = shorten_unambiguous_ref(base, 0);
+       base = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
        if (upstream_is_gone) {
                strbuf_addf(sb,
                        _("Your branch is based on '%s', but the upstream is gone.\n"),
                        strbuf_addf(sb,
                                _("  (use \"git pull\" to merge the remote branch into yours)\n"));
        }
+       free(base);
        return 1;
  }