Merge branch 'jc/unpack-trees-plug-leak'
authorJunio C Hamano <gitster@pobox.com>
Fri, 12 Dec 2014 22:31:33 +0000 (14:31 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 12 Dec 2014 22:31:33 +0000 (14:31 -0800)
* jc/unpack-trees-plug-leak:
unpack_trees: plug leakage of o->result

1  2 
unpack-trees.c
diff --combined unpack-trees.c
index 629c658c46a1b4f4bcd8bbe9770d7fd767ae2216,2515be6a608a517c84ec5df4c1fbeccbe9090b0b..3a66849e38b1940b1f3fc9c542ea864a86278687
@@@ -8,7 -8,6 +8,7 @@@
  #include "progress.h"
  #include "refs.h"
  #include "attr.h"
 +#include "split-index.h"
  
  /*
   * Error messages expected by scripts out of plumbing commands such as
@@@ -57,15 -56,17 +57,15 @@@ void setup_unpack_trees_porcelain(struc
        int i;
        const char **msgs = opts->msgs;
        const char *msg;
 -      char *tmp;
        const char *cmd2 = strcmp(cmd, "checkout") ? cmd : "switch branches";
 +
        if (advice_commit_before_merge)
                msg = "Your local changes to the following files would be overwritten by %s:\n%%s"
                        "Please, commit your changes or stash them before you can %s.";
        else
                msg = "Your local changes to the following files would be overwritten by %s:\n%%s";
 -      tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen(cmd2) - 2);
 -      sprintf(tmp, msg, cmd, cmd2);
 -      msgs[ERROR_WOULD_OVERWRITE] = tmp;
 -      msgs[ERROR_NOT_UPTODATE_FILE] = tmp;
 +      msgs[ERROR_WOULD_OVERWRITE] = msgs[ERROR_NOT_UPTODATE_FILE] =
 +              xstrfmt(msg, cmd, cmd2);
  
        msgs[ERROR_NOT_UPTODATE_DIR] =
                "Updating the following directories would lose untracked files in it:\n%s";
                        "Please move or remove them before you can %s.";
        else
                msg = "The following untracked working tree files would be %s by %s:\n%%s";
 -      tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen("removed") + strlen(cmd2) - 4);
 -      sprintf(tmp, msg, "removed", cmd, cmd2);
 -      msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] = tmp;
 -      tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen("overwritten") + strlen(cmd2) - 4);
 -      sprintf(tmp, msg, "overwritten", cmd, cmd2);
 -      msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] = tmp;
 +
 +      msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] = xstrfmt(msg, "removed", cmd, cmd2);
 +      msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] = xstrfmt(msg, "overwritten", cmd, cmd2);
  
        /*
         * Special case: ERROR_BIND_OVERLAP refers to a pair of paths, we
  static void do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
                         unsigned int set, unsigned int clear)
  {
 -      clear |= CE_HASHED | CE_UNHASHED;
 +      clear |= CE_HASHED;
  
        if (set & CE_REMOVE)
                set |= CE_WT_REMOVE;
  
 -      ce->next = NULL;
        ce->ce_flags = (ce->ce_flags & ~clear) | set;
        add_index_entry(&o->result, ce,
                        ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
@@@ -199,7 -204,7 +199,7 @@@ static int check_updates(struct unpack_
                                total++;
                }
  
 -              progress = start_progress_delay("Checking out files",
 +              progress = start_progress_delay(_("Checking out files"),
                                                total, 50, 1);
                cnt = 0;
        }
@@@ -242,9 -247,7 +242,9 @@@ static int verify_absent_sparse(const s
                                enum unpack_trees_error_types,
                                struct unpack_trees_options *o);
  
 -static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_options *o)
 +static int apply_sparse_checkout(struct index_state *istate,
 +                               struct cache_entry *ce,
 +                               struct unpack_trees_options *o)
  {
        int was_skip_worktree = ce_skip_worktree(ce);
  
                ce->ce_flags |= CE_SKIP_WORKTREE;
        else
                ce->ce_flags &= ~CE_SKIP_WORKTREE;
 +      if (was_skip_worktree != ce_skip_worktree(ce)) {
 +              ce->ce_flags |= CE_UPDATE_IN_BASE;
 +              istate->cache_changed |= CE_ENTRY_CHANGED;
 +      }
  
        /*
         * if (!was_skip_worktree && !ce_skip_worktree()) {
@@@ -624,6 -623,17 +624,6 @@@ static int unpack_failed(struct unpack_
        return -1;
  }
  
 -/* NEEDSWORK: give this a better name and share with tree-walk.c */
 -static int name_compare(const char *a, int a_len,
 -                      const char *b, int b_len)
 -{
 -      int len = (a_len < b_len) ? a_len : b_len;
 -      int cmp = memcmp(a, b, len);
 -      if (cmp)
 -              return cmp;
 -      return (a_len - b_len);
 -}
 -
  /*
   * The tree traversal is looking at name p.  If we have a matching entry,
   * return it.  If name p is a directory in the index, do not return
@@@ -820,24 -830,23 +820,24 @@@ static int unpack_callback(int n, unsig
  }
  
  static int clear_ce_flags_1(struct cache_entry **cache, int nr,
 -                          char *prefix, int prefix_len,
 +                          struct strbuf *prefix,
                            int select_mask, int clear_mask,
                            struct exclude_list *el, int defval);
  
  /* Whole directory matching */
  static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
 -                            char *prefix, int prefix_len,
 +                            struct strbuf *prefix,
                              char *basename,
                              int select_mask, int clear_mask,
                              struct exclude_list *el, int defval)
  {
        struct cache_entry **cache_end;
        int dtype = DT_DIR;
 -      int ret = is_excluded_from_list(prefix, prefix_len,
 +      int ret = is_excluded_from_list(prefix->buf, prefix->len,
                                        basename, &dtype, el);
 +      int rc;
  
 -      prefix[prefix_len++] = '/';
 +      strbuf_addch(prefix, '/');
  
        /* If undecided, use matching result of parent dir in defval */
        if (ret < 0)
  
        for (cache_end = cache; cache_end != cache + nr; cache_end++) {
                struct cache_entry *ce = *cache_end;
 -              if (strncmp(ce->name, prefix, prefix_len))
 +              if (strncmp(ce->name, prefix->buf, prefix->len))
                        break;
        }
  
         * calling clear_ce_flags_1(). That function will call
         * the expensive is_excluded_from_list() on every entry.
         */
 -      return clear_ce_flags_1(cache, cache_end - cache,
 -                              prefix, prefix_len,
 -                              select_mask, clear_mask,
 -                              el, ret);
 +      rc = clear_ce_flags_1(cache, cache_end - cache,
 +                            prefix,
 +                            select_mask, clear_mask,
 +                            el, ret);
 +      strbuf_setlen(prefix, prefix->len - 1);
 +      return rc;
  }
  
  /*
   * Top level path has prefix_len zero.
   */
  static int clear_ce_flags_1(struct cache_entry **cache, int nr,
 -                          char *prefix, int prefix_len,
 +                          struct strbuf *prefix,
                            int select_mask, int clear_mask,
                            struct exclude_list *el, int defval)
  {
                        continue;
                }
  
 -              if (prefix_len && strncmp(ce->name, prefix, prefix_len))
 +              if (prefix->len && strncmp(ce->name, prefix->buf, prefix->len))
                        break;
  
 -              name = ce->name + prefix_len;
 +              name = ce->name + prefix->len;
                slash = strchr(name, '/');
  
                /* If it's a directory, try whole directory match first */
                        int processed;
  
                        len = slash - name;
 -                      memcpy(prefix + prefix_len, name, len);
 +                      strbuf_add(prefix, name, len);
  
 -                      /*
 -                       * terminate the string (no trailing slash),
 -                       * clear_c_f_dir needs it
 -                       */
 -                      prefix[prefix_len + len] = '\0';
                        processed = clear_ce_flags_dir(cache, cache_end - cache,
 -                                                     prefix, prefix_len + len,
 -                                                     prefix + prefix_len,
 +                                                     prefix,
 +                                                     prefix->buf + prefix->len - len,
                                                       select_mask, clear_mask,
                                                       el, defval);
  
                        /* clear_c_f_dir eats a whole dir already? */
                        if (processed) {
                                cache += processed;
 +                              strbuf_setlen(prefix, prefix->len - len);
                                continue;
                        }
  
 -                      prefix[prefix_len + len++] = '/';
 +                      strbuf_addch(prefix, '/');
                        cache += clear_ce_flags_1(cache, cache_end - cache,
 -                                                prefix, prefix_len + len,
 +                                                prefix,
                                                  select_mask, clear_mask, el, defval);
 +                      strbuf_setlen(prefix, prefix->len - len - 1);
                        continue;
                }
  
@@@ -951,12 -961,9 +951,12 @@@ static int clear_ce_flags(struct cache_
                            int select_mask, int clear_mask,
                            struct exclude_list *el)
  {
 -      char prefix[PATH_MAX];
 +      static struct strbuf prefix = STRBUF_INIT;
 +
 +      strbuf_reset(&prefix);
 +
        return clear_ce_flags_1(cache, nr,
 -                              prefix, 0,
 +                              &prefix,
                                select_mask, clear_mask,
                                el, 0);
  }
@@@ -1016,7 -1023,6 +1016,7 @@@ int unpack_trees(unsigned len, struct t
        state.force = 1;
        state.quiet = 1;
        state.refresh_cache = 1;
 +      state.istate = &o->result;
  
        memset(&el, 0, sizeof(el));
        if (!core_apply_sparse_checkout || !o->update)
        o->result.timestamp.sec = o->src_index->timestamp.sec;
        o->result.timestamp.nsec = o->src_index->timestamp.nsec;
        o->result.version = o->src_index->version;
 +      o->result.split_index = o->src_index->split_index;
 +      if (o->result.split_index)
 +              o->result.split_index->refcount++;
 +      hashcpy(o->result.sha1, o->src_index->sha1);
        o->merge_size = len;
        mark_all_ce_unused(o->src_index);
  
                                ret = -1;
                        }
  
 -                      if (apply_sparse_checkout(ce, o)) {
 +                      if (apply_sparse_checkout(&o->result, ce, o)) {
                                if (!o->show_all_errors)
                                        goto return_failed;
                                ret = -1;
        if (o->dst_index) {
                discard_index(o->dst_index);
                *o->dst_index = o->result;
+       } else {
+               discard_index(&o->result);
        }
  
  done:
@@@ -1176,8 -1180,7 +1178,8 @@@ return_failed
  static int reject_merge(const struct cache_entry *ce,
                        struct unpack_trees_options *o)
  {
 -      return add_rejected_path(o, ERROR_WOULD_OVERWRITE, ce->name);
 +      return o->gently ? -1 :
 +              add_rejected_path(o, ERROR_WOULD_OVERWRITE, ce->name);
  }
  
  static int same(const struct cache_entry *a, const struct cache_entry *b)
@@@ -1256,7 -1259,7 +1258,7 @@@ static void invalidate_ce_path(const st
                               struct unpack_trees_options *o)
  {
        if (ce)
 -              cache_tree_invalidate_path(o->src_index->cache_tree, ce->name);
 +              cache_tree_invalidate_path(o->src_index, ce->name);
  }
  
  /*
@@@ -1632,7 -1635,7 +1634,7 @@@ int threeway_merge(const struct cache_e
        /* #14, #14ALT, #2ALT */
        if (remote && !df_conflict_head && head_match && !remote_match) {
                if (index && !same(index, remote) && !same(index, head))
 -                      return o->gently ? -1 : reject_merge(index, o);
 +                      return reject_merge(index, o);
                return merged_entry(remote, index, o);
        }
        /*
         * make sure that it matches head.
         */
        if (index && !same(index, head))
 -              return o->gently ? -1 : reject_merge(index, o);
 +              return reject_merge(index, o);
  
        if (head) {
                /* #5ALT, #15 */
@@@ -1769,8 -1772,9 +1771,8 @@@ int twoway_merge(const struct cache_ent
                                else
                                        return merged_entry(newtree, current, o);
                        }
 -                      return o->gently ? -1 : reject_merge(current, o);
 -              }
 -              else if ((!oldtree && !newtree) || /* 4 and 5 */
 +                      return reject_merge(current, o);
 +              } else if ((!oldtree && !newtree) || /* 4 and 5 */
                         (!oldtree && newtree &&
                          same(current, newtree)) || /* 6 and 7 */
                         (oldtree && newtree &&
                          !same(oldtree, newtree) && /* 18 and 19 */
                          same(current, newtree))) {
                        return keep_entry(current, o);
 -              }
 -              else if (oldtree && !newtree && same(current, oldtree)) {
 +              } else if (oldtree && !newtree && same(current, oldtree)) {
                        /* 10 or 11 */
                        return deleted_entry(oldtree, current, o);
 -              }
 -              else if (oldtree && newtree &&
 +              } else if (oldtree && newtree &&
                         same(current, oldtree) && !same(current, newtree)) {
                        /* 20 or 21 */
                        return merged_entry(newtree, current, o);
 -              }
 -              else {
 -                      /* all other failures */
 -                      if (oldtree)
 -                              return o->gently ? -1 : reject_merge(oldtree, o);
 -                      if (current)
 -                              return o->gently ? -1 : reject_merge(current, o);
 -                      if (newtree)
 -                              return o->gently ? -1 : reject_merge(newtree, o);
 -                      return -1;
 -              }
 +              } else
 +                      return reject_merge(current, o);
        }
        else if (newtree) {
                if (oldtree && !o->initial_checkout) {