Merge branch 'jp/index-with-corrupt-stages'
authorJunio C Hamano <gitster@pobox.com>
Fri, 19 Sep 2014 18:38:34 +0000 (11:38 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 19 Sep 2014 18:38:34 +0000 (11:38 -0700)
A broken reimplementation of Git could write an invalid index that
records both stage #0 and higher stage entries for the same path.
Notice and reject such an index, as there is no sensible fallback
(we do not know if the broken tool wanted to resolve and forgot to
remove higher stage entries, or if it wanted to unresolve and
forgot to remove the stage#0 entry).

* jp/index-with-corrupt-stages:
read_index_unmerged(): remove unnecessary loop index adjustment
read_index_from(): catch out of order entries when reading an index file

1  2 
read-cache.c
diff --combined read-cache.c
index b5917e0c0743af3c831f9571e19e269e8a1f6014,771d424b94acd1f6253efbaee44fca43de9076fa..2fc1182f2267b3e9aed799eaf7df234cd36fefb9
@@@ -14,8 -14,6 +14,8 @@@
  #include "resolve-undo.h"
  #include "strbuf.h"
  #include "varint.h"
 +#include "split-index.h"
 +#include "sigchain.h"
  
  static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
                                               unsigned int options);
  #define CACHE_EXT(s) ( (s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]) )
  #define CACHE_EXT_TREE 0x54524545     /* "TREE" */
  #define CACHE_EXT_RESOLVE_UNDO 0x52455543 /* "REUC" */
 +#define CACHE_EXT_LINK 0x6c696e6b       /* "link" */
 +
 +/* changes that can be kept in $GIT_DIR/index (basically all extensions) */
 +#define EXTMASK (RESOLVE_UNDO_CHANGED | CACHE_TREE_CHANGED | \
 +               CE_ENTRY_ADDED | CE_ENTRY_REMOVED | CE_ENTRY_CHANGED | \
 +               SPLIT_INDEX_ORDERED)
  
  struct index_state the_index;
 +static const char *alternate_index_output;
  
  static void set_index_entry(struct index_state *istate, int nr, struct cache_entry *ce)
  {
@@@ -56,12 -47,10 +56,12 @@@ static void replace_index_entry(struct 
  {
        struct cache_entry *old = istate->cache[nr];
  
 +      replace_index_entry_in_base(istate, old, ce);
        remove_name_hash(istate, old);
        free(old);
        set_index_entry(istate, nr, ce);
 -      istate->cache_changed = 1;
 +      ce->ce_flags |= CE_UPDATE_IN_BASE;
 +      istate->cache_changed |= CE_ENTRY_CHANGED;
  }
  
  void rename_index_entry_at(struct index_state *istate, int nr, const char *new_name)
        copy_cache_entry(new, old);
        new->ce_flags &= ~CE_HASHED;
        new->ce_namelen = namelen;
 +      new->index = 0;
        memcpy(new->name, new_name, namelen + 1);
  
 -      cache_tree_invalidate_path(istate->cache_tree, old->name);
 +      cache_tree_invalidate_path(istate, old->name);
        remove_index_entry_at(istate, nr);
        add_index_entry(istate, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
  }
@@@ -434,26 -422,18 +434,26 @@@ int df_name_compare(const char *name1, 
        return c1 - c2;
  }
  
 -int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2)
 +int name_compare(const char *name1, size_t len1, const char *name2, size_t len2)
  {
 -      int len = len1 < len2 ? len1 : len2;
 -      int cmp;
 -
 -      cmp = memcmp(name1, name2, len);
 +      size_t min_len = (len1 < len2) ? len1 : len2;
 +      int cmp = memcmp(name1, name2, min_len);
        if (cmp)
                return cmp;
        if (len1 < len2)
                return -1;
        if (len1 > len2)
                return 1;
 +      return 0;
 +}
 +
 +int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2)
 +{
 +      int cmp;
 +
 +      cmp = name_compare(name1, len1, name2, len2);
 +      if (cmp)
 +              return cmp;
  
        if (stage1 < stage2)
                return -1;
        return 0;
  }
  
 -int cache_name_compare(const char *name1, int len1, const char *name2, int len2)
 -{
 -      return cache_name_stage_compare(name1, len1, 0, name2, len2, 0);
 -}
 -
  static int index_name_stage_pos(const struct index_state *istate, const char *name, int namelen, int stage)
  {
        int first, last;
@@@ -495,8 -480,8 +495,8 @@@ int remove_index_entry_at(struct index_
  
        record_resolve_undo(istate, ce);
        remove_name_hash(istate, ce);
 -      free(ce);
 -      istate->cache_changed = 1;
 +      save_or_free_index_entry(istate, ce);
 +      istate->cache_changed |= CE_ENTRY_REMOVED;
        istate->cache_nr--;
        if (pos >= istate->cache_nr)
                return 0;
@@@ -519,14 -504,12 +519,14 @@@ void remove_marked_cache_entries(struc
        for (i = j = 0; i < istate->cache_nr; i++) {
                if (ce_array[i]->ce_flags & CE_REMOVE) {
                        remove_name_hash(istate, ce_array[i]);
 -                      free(ce_array[i]);
 +                      save_or_free_index_entry(istate, ce_array[i]);
                }
                else
                        ce_array[j++] = ce_array[i];
        }
 -      istate->cache_changed = 1;
 +      if (j == istate->cache_nr)
 +              return;
 +      istate->cache_changed |= CE_ENTRY_REMOVED;
        istate->cache_nr = j;
  }
  
@@@ -535,7 -518,7 +535,7 @@@ int remove_file_from_index(struct index
        int pos = index_name_pos(istate, path, strlen(path));
        if (pos < 0)
                pos = -pos-1;
 -      cache_tree_invalidate_path(istate->cache_tree, path);
 +      cache_tree_invalidate_path(istate, path);
        while (pos < istate->cache_nr && !strcmp(istate->cache[pos]->name, path))
                remove_index_entry_at(istate, pos);
        return 0;
@@@ -584,9 -567,7 +584,9 @@@ static int different_name(struct cache_
   * So we use the CE_ADDED flag to verify that the alias was an old
   * one before we accept it as
   */
 -static struct cache_entry *create_alias_ce(struct cache_entry *ce, struct cache_entry *alias)
 +static struct cache_entry *create_alias_ce(struct index_state *istate,
 +                                         struct cache_entry *ce,
 +                                         struct cache_entry *alias)
  {
        int len;
        struct cache_entry *new;
        new = xcalloc(1, cache_entry_size(len));
        memcpy(new->name, alias->name, len);
        copy_cache_entry(new, ce);
 -      free(ce);
 +      save_or_free_index_entry(istate, ce);
        return new;
  }
  
@@@ -692,7 -673,7 +692,7 @@@ int add_to_index(struct index_state *is
                set_object_name_for_intent_to_add_entry(ce);
  
        if (ignore_case && alias && different_name(ce, alias))
 -              ce = create_alias_ce(ce, alias);
 +              ce = create_alias_ce(istate, ce, alias);
        ce->ce_flags |= CE_ADDED;
  
        /* It was suspected to be racily clean, but it turns out to be Ok */
@@@ -955,8 -936,7 +955,8 @@@ static int add_index_entry_with_check(s
        int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
        int new_only = option & ADD_CACHE_NEW_ONLY;
  
 -      cache_tree_invalidate_path(istate->cache_tree, ce->name);
 +      if (!(option & ADD_CACHE_KEEP_CACHE_TREE))
 +              cache_tree_invalidate_path(istate, ce->name);
        pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
  
        /* existing match? Just replace it. */
@@@ -1019,7 -999,7 +1019,7 @@@ int add_index_entry(struct index_state 
                        istate->cache + pos,
                        (istate->cache_nr - pos - 1) * sizeof(ce));
        set_index_entry(istate, pos, ce);
 -      istate->cache_changed = 1;
 +      istate->cache_changed |= CE_ENTRY_ADDED;
        return 0;
  }
  
@@@ -1064,14 -1044,6 +1064,14 @@@ static struct cache_entry *refresh_cach
                return ce;
        }
  
 +      if (has_symlink_leading_path(ce->name, ce_namelen(ce))) {
 +              if (ignore_missing)
 +                      return ce;
 +              if (err)
 +                      *err = ENOENT;
 +              return NULL;
 +      }
 +
        if (lstat(ce->name, &st) < 0) {
                if (ignore_missing && errno == ENOENT)
                        return ce;
            !(ce->ce_flags & CE_VALID))
                updated->ce_flags &= ~CE_VALID;
  
 +      /* istate->cache_changed is updated in the caller */
        return updated;
  }
  
@@@ -1208,8 -1179,7 +1208,8 @@@ int refresh_index(struct index_state *i
                                 * means the index is not valid anymore.
                                 */
                                ce->ce_flags &= ~CE_VALID;
 -                              istate->cache_changed = 1;
 +                              ce->ce_flags |= CE_UPDATE_IN_BASE;
 +                              istate->cache_changed |= CE_ENTRY_CHANGED;
                        }
                        if (quiet)
                                continue;
@@@ -1246,16 -1216,24 +1246,16 @@@ static struct cache_entry *refresh_cach
  
  #define INDEX_FORMAT_DEFAULT 3
  
 -static int index_format_config(const char *var, const char *value, void *cb)
 -{
 -      unsigned int *version = cb;
 -      if (!strcmp(var, "index.version")) {
 -              *version = git_config_int(var, value);
 -              return 0;
 -      }
 -      return 1;
 -}
 -
  static unsigned int get_index_format_default(void)
  {
        char *envversion = getenv("GIT_INDEX_VERSION");
        char *endp;
 +      int value;
        unsigned int version = INDEX_FORMAT_DEFAULT;
  
        if (!envversion) {
 -              git_config(index_format_config, &version);
 +              if (!git_config_get_int("index.version", &value))
 +                      version = value;
                if (version < INDEX_FORMAT_LB || INDEX_FORMAT_UB < version) {
                        warning(_("index.version set, but the value is invalid.\n"
                                  "Using version %i"), INDEX_FORMAT_DEFAULT);
@@@ -1353,10 -1331,6 +1353,10 @@@ static int read_index_extension(struct 
        case CACHE_EXT_RESOLVE_UNDO:
                istate->resolve_undo = resolve_undo_read(data, sz);
                break;
 +      case CACHE_EXT_LINK:
 +              if (read_link_extension(istate, data, sz))
 +                      return -1;
 +              break;
        default:
                if (*ext < 'A' || 'Z' < *ext)
                        return error("index uses %.4s extension, which we do not understand",
@@@ -1391,7 -1365,6 +1391,7 @@@ static struct cache_entry *cache_entry_
        ce->ce_stat_data.sd_size  = get_be32(&ondisk->size);
        ce->ce_flags = flags & ~CE_NAMEMASK;
        ce->ce_namelen = len;
 +      ce->index = 0;
        hashcpy(ce->sha1, ondisk->sha1);
        memcpy(ce->name, name, len);
        ce->name[len] = '\0';
@@@ -1465,8 -1438,23 +1465,23 @@@ static struct cache_entry *create_from_
        return ce;
  }
  
+ static void check_ce_order(struct cache_entry *ce, struct cache_entry *next_ce)
+ {
+       int name_compare = strcmp(ce->name, next_ce->name);
+       if (0 < name_compare)
+               die("unordered stage entries in index");
+       if (!name_compare) {
+               if (!ce_stage(ce))
+                       die("multiple stage entries for merged file '%s'",
+                               ce->name);
+               if (ce_stage(ce) > ce_stage(next_ce))
+                       die("unordered stage entries for '%s'",
+                               ce->name);
+       }
+ }
  /* remember to discard_cache() before reading a different cache! */
 -int read_index_from(struct index_state *istate, const char *path)
 +int do_read_index(struct index_state *istate, const char *path, int must_exist)
  {
        int fd, i;
        struct stat st;
        istate->timestamp.nsec = 0;
        fd = open(path, O_RDONLY);
        if (fd < 0) {
 -              if (errno == ENOENT)
 +              if (!must_exist && errno == ENOENT)
                        return 0;
 -              die_errno("index file open failed");
 +              die_errno("%s: index file open failed", path);
        }
  
        if (fstat(fd, &st))
        if (verify_hdr(hdr, mmap_size) < 0)
                goto unmap;
  
 -      hashcpy(istate->sha1, (unsigned char *)hdr + mmap_size - 20);
 +      hashcpy(istate->sha1, (const unsigned char *)hdr + mmap_size - 20);
        istate->version = ntohl(hdr->hdr_version);
        istate->cache_nr = ntohl(hdr->hdr_entries);
        istate->cache_alloc = alloc_nr(istate->cache_nr);
                ce = create_from_disk(disk_ce, &consumed, previous_name);
                set_index_entry(istate, i, ce);
  
+               if (i > 0)
+                       check_ce_order(istate->cache[i - 1], ce);
                src_offset += consumed;
        }
        strbuf_release(&previous_name_buf);
@@@ -1558,40 -1549,6 +1576,40 @@@ unmap
        die("index file corrupt");
  }
  
 +int read_index_from(struct index_state *istate, const char *path)
 +{
 +      struct split_index *split_index;
 +      int ret;
 +
 +      /* istate->initialized covers both .git/index and .git/sharedindex.xxx */
 +      if (istate->initialized)
 +              return istate->cache_nr;
 +
 +      ret = do_read_index(istate, path, 0);
 +      split_index = istate->split_index;
 +      if (!split_index)
 +              return ret;
 +
 +      if (is_null_sha1(split_index->base_sha1))
 +              return ret;
 +
 +      if (split_index->base)
 +              discard_index(split_index->base);
 +      else
 +              split_index->base = xcalloc(1, sizeof(*split_index->base));
 +      ret = do_read_index(split_index->base,
 +                          git_path("sharedindex.%s",
 +                                   sha1_to_hex(split_index->base_sha1)), 1);
 +      if (hashcmp(split_index->base_sha1, split_index->base->sha1))
 +              die("broken index, expect %s in %s, got %s",
 +                  sha1_to_hex(split_index->base_sha1),
 +                  git_path("sharedindex.%s",
 +                                   sha1_to_hex(split_index->base_sha1)),
 +                  sha1_to_hex(split_index->base->sha1));
 +      merge_base_index(istate);
 +      return ret;
 +}
 +
  int is_index_unborn(struct index_state *istate)
  {
        return (!istate->cache_nr && !istate->timestamp.sec);
@@@ -1601,15 -1558,8 +1619,15 @@@ int discard_index(struct index_state *i
  {
        int i;
  
 -      for (i = 0; i < istate->cache_nr; i++)
 +      for (i = 0; i < istate->cache_nr; i++) {
 +              if (istate->cache[i]->index &&
 +                  istate->split_index &&
 +                  istate->split_index->base &&
 +                  istate->cache[i]->index <= istate->split_index->base->cache_nr &&
 +                  istate->cache[i] == istate->split_index->base->cache[istate->cache[i]->index - 1])
 +                      continue;
                free(istate->cache[i]);
 +      }
        resolve_undo_clear_index(istate);
        istate->cache_nr = 0;
        istate->cache_changed = 0;
        free(istate->cache);
        istate->cache = NULL;
        istate->cache_alloc = 0;
 +      discard_split_index(istate);
        return 0;
  }
  
@@@ -1682,7 -1631,7 +1700,7 @@@ static int write_index_ext_header(git_S
                (ce_write(context, fd, &sz, 4) < 0)) ? -1 : 0;
  }
  
 -static int ce_flush(git_SHA_CTX *context, int fd)
 +static int ce_flush(git_SHA_CTX *context, int fd, unsigned char *sha1)
  {
        unsigned int left = write_buffer_len;
  
  
        /* Append the SHA1 signature at the end */
        git_SHA1_Final(write_buffer + left, context);
 +      hashcpy(sha1, write_buffer + left);
        left += 20;
        return (write_in_full(fd, write_buffer, left) != left) ? -1 : 0;
  }
@@@ -1772,7 -1720,7 +1790,7 @@@ static char *copy_cache_entry_to_ondisk
        ondisk->size = htonl(ce->ce_stat_data.sd_size);
        hashcpy(ondisk->sha1, ce->sha1);
  
 -      flags = ce->ce_flags;
 +      flags = ce->ce_flags & ~CE_NAMEMASK;
        flags |= (ce_namelen(ce) >= CE_NAMEMASK ? CE_NAMEMASK : ce_namelen(ce));
        ondisk->flags = htons(flags);
        if (ce->ce_flags & CE_EXTENDED) {
@@@ -1791,15 -1739,9 +1809,15 @@@ static int ce_write_entry(git_SHA_CTX *
  {
        int size;
        struct ondisk_cache_entry *ondisk;
 +      int saved_namelen = saved_namelen; /* compiler workaround */
        char *name;
        int result;
  
 +      if (ce->ce_flags & CE_STRIP_NAME) {
 +              saved_namelen = ce_namelen(ce);
 +              ce->ce_namelen = 0;
 +      }
 +
        if (!previous_name) {
                size = ondisk_ce_size(ce);
                ondisk = xcalloc(1, size);
                strbuf_splice(previous_name, common, to_remove,
                              ce->name + common, ce_namelen(ce) - common);
        }
 +      if (ce->ce_flags & CE_STRIP_NAME) {
 +              ce->ce_namelen = saved_namelen;
 +              ce->ce_flags &= ~CE_STRIP_NAME;
 +      }
  
        result = ce_write(c, fd, ondisk, size);
        free(ondisk);
@@@ -1904,13 -1842,13 +1922,13 @@@ static int has_racy_timestamp(struct in
  void update_index_if_able(struct index_state *istate, struct lock_file *lockfile)
  {
        if ((istate->cache_changed || has_racy_timestamp(istate)) &&
 -          verify_index(istate) && !write_index(istate, lockfile->fd))
 -              commit_locked_index(lockfile);
 -      else
 +          verify_index(istate) &&
 +          write_locked_index(istate, lockfile, COMMIT_LOCK))
                rollback_lock_file(lockfile);
  }
  
 -int write_index(struct index_state *istate, int newfd)
 +static int do_write_index(struct index_state *istate, int newfd,
 +                        int strip_extensions)
  {
        git_SHA_CTX c;
        struct cache_header hdr;
                }
        }
  
 -      if (!istate->version)
 +      if (!istate->version) {
                istate->version = get_index_format_default();
 +              if (getenv("GIT_TEST_SPLIT_INDEX"))
 +                      init_split_index(istate);
 +      }
  
        /* demote version 3 to version 2 when the latter suffices */
        if (istate->version == 3 || istate->version == 2)
        strbuf_release(&previous_name_buf);
  
        /* Write extension data here */
 -      if (istate->cache_tree) {
 +      if (!strip_extensions && istate->split_index) {
 +              struct strbuf sb = STRBUF_INIT;
 +
 +              err = write_link_extension(&sb, istate) < 0 ||
 +                      write_index_ext_header(&c, newfd, CACHE_EXT_LINK,
 +                                             sb.len) < 0 ||
 +                      ce_write(&c, newfd, sb.buf, sb.len) < 0;
 +              strbuf_release(&sb);
 +              if (err)
 +                      return -1;
 +      }
 +      if (!strip_extensions && istate->cache_tree) {
                struct strbuf sb = STRBUF_INIT;
  
                cache_tree_write(&sb, istate->cache_tree);
                if (err)
                        return -1;
        }
 -      if (istate->resolve_undo) {
 +      if (!strip_extensions && istate->resolve_undo) {
                struct strbuf sb = STRBUF_INIT;
  
                resolve_undo_write(&sb, istate->resolve_undo);
                        return -1;
        }
  
 -      if (ce_flush(&c, newfd) || fstat(newfd, &st))
 +      if (ce_flush(&c, newfd, istate->sha1) || fstat(newfd, &st))
                return -1;
        istate->timestamp.sec = (unsigned int)st.st_mtime;
        istate->timestamp.nsec = ST_MTIME_NSEC(st);
        return 0;
  }
  
 +void set_alternate_index_output(const char *name)
 +{
 +      alternate_index_output = name;
 +}
 +
 +static int commit_locked_index(struct lock_file *lk)
 +{
 +      if (alternate_index_output) {
 +              if (lk->fd >= 0 && close_lock_file(lk))
 +                      return -1;
 +              if (rename(lk->filename, alternate_index_output))
 +                      return -1;
 +              lk->filename[0] = 0;
 +              return 0;
 +      } else {
 +              return commit_lock_file(lk);
 +      }
 +}
 +
 +static int do_write_locked_index(struct index_state *istate, struct lock_file *lock,
 +                               unsigned flags)
 +{
 +      int ret = do_write_index(istate, lock->fd, 0);
 +      if (ret)
 +              return ret;
 +      assert((flags & (COMMIT_LOCK | CLOSE_LOCK)) !=
 +             (COMMIT_LOCK | CLOSE_LOCK));
 +      if (flags & COMMIT_LOCK)
 +              return commit_locked_index(lock);
 +      else if (flags & CLOSE_LOCK)
 +              return close_lock_file(lock);
 +      else
 +              return ret;
 +}
 +
 +static int write_split_index(struct index_state *istate,
 +                           struct lock_file *lock,
 +                           unsigned flags)
 +{
 +      int ret;
 +      prepare_to_write_split_index(istate);
 +      ret = do_write_locked_index(istate, lock, flags);
 +      finish_writing_split_index(istate);
 +      return ret;
 +}
 +
 +static char *temporary_sharedindex;
 +
 +static void remove_temporary_sharedindex(void)
 +{
 +      if (temporary_sharedindex) {
 +              unlink_or_warn(temporary_sharedindex);
 +              free(temporary_sharedindex);
 +              temporary_sharedindex = NULL;
 +      }
 +}
 +
 +static void remove_temporary_sharedindex_on_signal(int signo)
 +{
 +      remove_temporary_sharedindex();
 +      sigchain_pop(signo);
 +      raise(signo);
 +}
 +
 +static int write_shared_index(struct index_state *istate,
 +                            struct lock_file *lock, unsigned flags)
 +{
 +      struct split_index *si = istate->split_index;
 +      static int installed_handler;
 +      int fd, ret;
 +
 +      temporary_sharedindex = git_pathdup("sharedindex_XXXXXX");
 +      fd = mkstemp(temporary_sharedindex);
 +      if (fd < 0) {
 +              free(temporary_sharedindex);
 +              temporary_sharedindex = NULL;
 +              hashclr(si->base_sha1);
 +              return do_write_locked_index(istate, lock, flags);
 +      }
 +      if (!installed_handler) {
 +              atexit(remove_temporary_sharedindex);
 +              sigchain_push_common(remove_temporary_sharedindex_on_signal);
 +      }
 +      move_cache_to_base_index(istate);
 +      ret = do_write_index(si->base, fd, 1);
 +      close(fd);
 +      if (ret) {
 +              remove_temporary_sharedindex();
 +              return ret;
 +      }
 +      ret = rename(temporary_sharedindex,
 +                   git_path("sharedindex.%s", sha1_to_hex(si->base->sha1)));
 +      free(temporary_sharedindex);
 +      temporary_sharedindex = NULL;
 +      if (!ret)
 +              hashcpy(si->base_sha1, si->base->sha1);
 +      return ret;
 +}
 +
 +int write_locked_index(struct index_state *istate, struct lock_file *lock,
 +                     unsigned flags)
 +{
 +      struct split_index *si = istate->split_index;
 +
 +      if (!si || alternate_index_output ||
 +          (istate->cache_changed & ~EXTMASK)) {
 +              if (si)
 +                      hashclr(si->base_sha1);
 +              return do_write_locked_index(istate, lock, flags);
 +      }
 +
 +      if (getenv("GIT_TEST_SPLIT_INDEX")) {
 +              int v = si->base_sha1[0];
 +              if ((v & 15) < 6)
 +                      istate->cache_changed |= SPLIT_INDEX_ORDERED;
 +      }
 +      if (istate->cache_changed & SPLIT_INDEX_ORDERED) {
 +              int ret = write_shared_index(istate, lock, flags);
 +              if (ret)
 +                      return ret;
 +      }
 +
 +      return write_split_index(istate, lock, flags);
 +}
 +
  /*
   * Read the index file that is potentially unmerged into given
   * index_state, dropping any unmerged entries.  Returns true if
@@@ -2172,7 -1971,6 +2190,6 @@@ int read_index_unmerged(struct index_st
                if (add_index_entry(istate, new_ce, 0))
                        return error("%s: cannot drop to stage #0",
                                     new_ce->name);
-               i = index_name_pos(istate, new_ce->name, len);
        }
        return unmerged;
  }