unpack-trees code works on multiple indexes specified in
unpack_trees_options. Although they normally all refer to the_index at
the call site, that is the caller's business. unpack-trees.c should
not make any assumption about that and should use the correct index
field in unpack_trees_options.

This patch is actually confusing because sometimes the function
parameter is also named "the_index" while some other times "the_index"
is the global variable because the function just does not have a
parameter of the same name! The only subtle difference is that the
function parameter is a pointer while the global one is not.

This is more of a bug report than an actual fix because I'm not sure
if "o->src_index" is always the correct answer instead of "the_index"
here. But this is very similar to 7db118303a (unpack_trees: fix
breakage when o->src_index != o->dst_index - 2018-04-23) and could
potentially break things again...

Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 unpack-trees.c | 45 ++++++++++++++++++++++++++-------------------
 1 file changed, 26 insertions(+), 19 deletions(-)

diff --git a/unpack-trees.c b/unpack-trees.c
index 3a85a02a77..114496cfc2 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -18,6 +18,9 @@
 #include "fsmonitor.h"
 #include "fetch-object.h"
 
+/* Do not use the_index here, you probably want o->src_index */
+#define the_index the_index_should_not_be_used here
+
 /*
  * Error messages expected by scripts out of plumbing commands such as
  * read-tree.  Non-scripted Porcelain is not required to use these messages
@@ -1085,13 +1088,15 @@ static int unpack_callback(int n, unsigned long mask, 
unsigned long dirmask, str
        return mask;
 }
 
-static int clear_ce_flags_1(struct cache_entry **cache, int nr,
+static int clear_ce_flags_1(struct index_state *istate,
+                           struct cache_entry **cache, int nr,
                            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,
+static int clear_ce_flags_dir(struct index_state *istate,
+                             struct cache_entry **cache, int nr,
                              struct strbuf *prefix,
                              char *basename,
                              int select_mask, int clear_mask,
@@ -1100,7 +1105,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, 
int nr,
        struct cache_entry **cache_end;
        int dtype = DT_DIR;
        int ret = is_excluded_from_list(prefix->buf, prefix->len,
-                                       basename, &dtype, el, &the_index);
+                                       basename, &dtype, el, istate);
        int rc;
 
        strbuf_addch(prefix, '/');
@@ -1122,7 +1127,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, 
int nr,
         * calling clear_ce_flags_1(). That function will call
         * the expensive is_excluded_from_list() on every entry.
         */
-       rc = clear_ce_flags_1(cache, cache_end - cache,
+       rc = clear_ce_flags_1(istate, cache, cache_end - cache,
                              prefix,
                              select_mask, clear_mask,
                              el, ret);
@@ -1145,7 +1150,8 @@ static int clear_ce_flags_dir(struct cache_entry **cache, 
int nr,
  *   cache[0]->name[0..(prefix_len-1)]
  * Top level path has prefix_len zero.
  */
-static int clear_ce_flags_1(struct cache_entry **cache, int nr,
+static int clear_ce_flags_1(struct index_state *istate,
+                           struct cache_entry **cache, int nr,
                            struct strbuf *prefix,
                            int select_mask, int clear_mask,
                            struct exclude_list *el, int defval)
@@ -1179,7 +1185,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, 
int nr,
                        len = slash - name;
                        strbuf_add(prefix, name, len);
 
-                       processed = clear_ce_flags_dir(cache, cache_end - cache,
+                       processed = clear_ce_flags_dir(istate, cache, cache_end 
- cache,
                                                       prefix,
                                                       prefix->buf + 
prefix->len - len,
                                                       select_mask, clear_mask,
@@ -1193,7 +1199,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, 
int nr,
                        }
 
                        strbuf_addch(prefix, '/');
-                       cache += clear_ce_flags_1(cache, cache_end - cache,
+                       cache += clear_ce_flags_1(istate, cache, cache_end - 
cache,
                                                  prefix,
                                                  select_mask, clear_mask, el, 
defval);
                        strbuf_setlen(prefix, prefix->len - len - 1);
@@ -1203,7 +1209,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, 
int nr,
                /* Non-directory */
                dtype = ce_to_dtype(ce);
                ret = is_excluded_from_list(ce->name, ce_namelen(ce),
-                                           name, &dtype, el, &the_index);
+                                           name, &dtype, el, istate);
                if (ret < 0)
                        ret = defval;
                if (ret > 0)
@@ -1213,15 +1219,17 @@ static int clear_ce_flags_1(struct cache_entry **cache, 
int nr,
        return nr - (cache_end - cache);
 }
 
-static int clear_ce_flags(struct cache_entry **cache, int nr,
-                           int select_mask, int clear_mask,
-                           struct exclude_list *el)
+static int clear_ce_flags(struct index_state *istate,
+                         int select_mask, int clear_mask,
+                         struct exclude_list *el)
 {
        static struct strbuf prefix = STRBUF_INIT;
 
        strbuf_reset(&prefix);
 
-       return clear_ce_flags_1(cache, nr,
+       return clear_ce_flags_1(istate,
+                               istate->cache,
+                               istate->cache_nr,
                                &prefix,
                                select_mask, clear_mask,
                                el, 0);
@@ -1231,7 +1239,7 @@ static int clear_ce_flags(struct cache_entry **cache, int 
nr,
  * Set/Clear CE_NEW_SKIP_WORKTREE according to $GIT_DIR/info/sparse-checkout
  */
 static void mark_new_skip_worktree(struct exclude_list *el,
-                                  struct index_state *the_index,
+                                  struct index_state *istate,
                                   int select_flag, int skip_wt_flag)
 {
        int i;
@@ -1240,8 +1248,8 @@ static void mark_new_skip_worktree(struct exclude_list 
*el,
         * 1. Pretend the narrowest worktree: only unmerged entries
         * are checked out
         */
-       for (i = 0; i < the_index->cache_nr; i++) {
-               struct cache_entry *ce = the_index->cache[i];
+       for (i = 0; i < istate->cache_nr; i++) {
+               struct cache_entry *ce = istate->cache[i];
 
                if (select_flag && !(ce->ce_flags & select_flag))
                        continue;
@@ -1256,8 +1264,7 @@ static void mark_new_skip_worktree(struct exclude_list 
*el,
         * 2. Widen worktree according to sparse-checkout file.
         * Matched entries will have skip_wt_flag cleared (i.e. "in")
         */
-       clear_ce_flags(the_index->cache, the_index->cache_nr,
-                      select_flag, skip_wt_flag, el);
+       clear_ce_flags(istate, select_flag, skip_wt_flag, el);
 }
 
 static int verify_absent(const struct cache_entry *,
@@ -1636,7 +1643,7 @@ static int verify_clean_subdirectory(const struct 
cache_entry *ce,
        memset(&d, 0, sizeof(d));
        if (o->dir)
                d.exclude_per_dir = o->dir->exclude_per_dir;
-       i = read_directory(&d, &the_index, pathbuf, namelen+1, NULL);
+       i = read_directory(&d, o->src_index, pathbuf, namelen+1, NULL);
        if (i)
                return o->gently ? -1 :
                        add_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name);
@@ -1678,7 +1685,7 @@ static int check_ok_to_remove(const char *name, int len, 
int dtype,
                return 0;
 
        if (o->dir &&
-           is_excluded(o->dir, &the_index, name, &dtype))
+           is_excluded(o->dir, o->src_index, name, &dtype))
                /*
                 * ce->name is explicitly excluded, so it is Ok to
                 * overwrite it.
-- 
2.18.0.rc0.309.g77c7720784

Reply via email to