Merge branch 'pc/dir-count-slashes'
authorJunio C Hamano <gitster@pobox.com>
Thu, 22 Jun 2017 21:15:21 +0000 (14:15 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 22 Jun 2017 21:15:21 +0000 (14:15 -0700)
Three instances of the same helper function have been consolidated
to one.

* pc/dir-count-slashes:
dir: create function count_slashes()

1  2 
apply.c
builtin/show-branch.c
dir.c
dir.h
diff --combined apply.c
index 854faa67795bcd356b33420f46260f208c2ec047,27d5dc0d4500d420d00db7f6b240d135108078c3..679ed7732d2385c4d7704f60335514b2b5f75c39
+++ b/apply.c
@@@ -762,17 -762,6 +762,6 @@@ static char *find_name_traditional(stru
        return find_name_common(state, line, def, p_value, line + len, 0);
  }
  
- static int count_slashes(const char *cp)
- {
-       int cnt = 0;
-       char ch;
-       while ((ch = *cp++))
-               if (ch == '/')
-                       cnt++;
-       return cnt;
- }
  /*
   * Given the string after "--- " or "+++ ", guess the appropriate
   * p_value for the given patch.
@@@ -3741,7 -3730,7 +3730,7 @@@ static int check_to_create(struct apply
                        return 0;
  
                return EXISTS_IN_WORKTREE;
 -      } else if ((errno != ENOENT) && (errno != ENOTDIR)) {
 +      } else if (!is_missing_file_error(errno)) {
                return error_errno("%s", new_name);
        }
        return 0;
@@@ -4091,181 -4080,181 +4080,181 @@@ static int build_fake_ancestor(struct a
        res = write_locked_index(&result, &lock, COMMIT_LOCK);
        discard_index(&result);
  
 -       if (res)
 -               return error(_("could not write temporary index to %s"),
 -                            state->fake_ancestor);
 +      if (res)
 +              return error(_("could not write temporary index to %s"),
 +                           state->fake_ancestor);
  
 -       return 0;
 - }
 +      return 0;
 +}
  
 - static void stat_patch_list(struct apply_state *state, struct patch *patch)
 - {
 -       int files, adds, dels;
 +static void stat_patch_list(struct apply_state *state, struct patch *patch)
 +{
 +      int files, adds, dels;
  
 -       for (files = adds = dels = 0 ; patch ; patch = patch->next) {
 -               files++;
 -               adds += patch->lines_added;
 -               dels += patch->lines_deleted;
 -               show_stats(state, patch);
 -       }
 +      for (files = adds = dels = 0 ; patch ; patch = patch->next) {
 +              files++;
 +              adds += patch->lines_added;
 +              dels += patch->lines_deleted;
 +              show_stats(state, patch);
 +      }
  
 -       print_stat_summary(stdout, files, adds, dels);
 - }
 +      print_stat_summary(stdout, files, adds, dels);
 +}
  
 - static void numstat_patch_list(struct apply_state *state,
 -                              struct patch *patch)
 - {
 -       for ( ; patch; patch = patch->next) {
 -               const char *name;
 -               name = patch->new_name ? patch->new_name : patch->old_name;
 -               if (patch->is_binary)
 -                       printf("-\t-\t");
 -               else
 -                       printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
 -               write_name_quoted(name, stdout, state->line_termination);
 -       }
 - }
 -
 - static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name)
 - {
 -       if (mode)
 -               printf(" %s mode %06o %s\n", newdelete, mode, name);
 -       else
 -               printf(" %s %s\n", newdelete, name);
 - }
 -
 - static void show_mode_change(struct patch *p, int show_name)
 - {
 -       if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) {
 -               if (show_name)
 -                       printf(" mode change %06o => %06o %s\n",
 -                              p->old_mode, p->new_mode, p->new_name);
 -               else
 -                       printf(" mode change %06o => %06o\n",
 -                              p->old_mode, p->new_mode);
 -       }
 - }
 -
 - static void show_rename_copy(struct patch *p)
 - {
 -       const char *renamecopy = p->is_rename ? "rename" : "copy";
 -       const char *old, *new;
 -
 -       /* Find common prefix */
 -       old = p->old_name;
 -       new = p->new_name;
 -       while (1) {
 -               const char *slash_old, *slash_new;
 -               slash_old = strchr(old, '/');
 -               slash_new = strchr(new, '/');
 -               if (!slash_old ||
 -                   !slash_new ||
 -                   slash_old - old != slash_new - new ||
 -                   memcmp(old, new, slash_new - new))
 -                       break;
 -               old = slash_old + 1;
 -               new = slash_new + 1;
 -       }
 -       /* p->old_name thru old is the common prefix, and old and new
 -        * through the end of names are renames
 -        */
 -       if (old != p->old_name)
 -               printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
 -                      (int)(old - p->old_name), p->old_name,
 -                      old, new, p->score);
 -       else
 -               printf(" %s %s => %s (%d%%)\n", renamecopy,
 -                      p->old_name, p->new_name, p->score);
 -       show_mode_change(p, 0);
 - }
 -
 - static void summary_patch_list(struct patch *patch)
 - {
 -       struct patch *p;
 -
 -       for (p = patch; p; p = p->next) {
 -               if (p->is_new)
 -                       show_file_mode_name("create", p->new_mode, p->new_name);
 -               else if (p->is_delete)
 -                       show_file_mode_name("delete", p->old_mode, p->old_name);
 -               else {
 -                       if (p->is_rename || p->is_copy)
 -                               show_rename_copy(p);
 -                       else {
 -                               if (p->score) {
 -                                       printf(" rewrite %s (%d%%)\n",
 -                                              p->new_name, p->score);
 -                                       show_mode_change(p, 0);
 -                               }
 -                               else
 -                                       show_mode_change(p, 1);
 -                       }
 -               }
 -       }
 - }
 -
 - static void patch_stats(struct apply_state *state, struct patch *patch)
 - {
 -       int lines = patch->lines_added + patch->lines_deleted;
 -
 -       if (lines > state->max_change)
 -               state->max_change = lines;
 -       if (patch->old_name) {
 -               int len = quote_c_style(patch->old_name, NULL, NULL, 0);
 -               if (!len)
 -                       len = strlen(patch->old_name);
 -               if (len > state->max_len)
 -                       state->max_len = len;
 -       }
 -       if (patch->new_name) {
 -               int len = quote_c_style(patch->new_name, NULL, NULL, 0);
 -               if (!len)
 -                       len = strlen(patch->new_name);
 -               if (len > state->max_len)
 -                       state->max_len = len;
 -       }
 - }
 -
 - static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
 - {
 -       if (state->update_index) {
 -               if (remove_file_from_cache(patch->old_name) < 0)
 -                       return error(_("unable to remove %s from index"), patch->old_name);
 -       }
 -       if (!state->cached) {
 -               if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
 -                       remove_path(patch->old_name);
 -               }
 -       }
 -       return 0;
 - }
 -
 - static int add_index_file(struct apply_state *state,
 -                         const char *path,
 -                         unsigned mode,
 -                         void *buf,
 -                         unsigned long size)
 - {
 -       struct stat st;
 -       struct cache_entry *ce;
 -       int namelen = strlen(path);
 -       unsigned ce_size = cache_entry_size(namelen);
 -
 -       if (!state->update_index)
 -               return 0;
 -
 -       ce = xcalloc(1, ce_size);
 -       memcpy(ce->name, path, namelen);
 -       ce->ce_mode = create_ce_mode(mode);
 -       ce->ce_flags = create_ce_flags(0);
 -       ce->ce_namelen = namelen;
 -       if (S_ISGITLINK(mode)) {
 -               const char *s;
 -
 -               if (!skip_prefix(buf, "Subproject commit ", &s) ||
 -                   get_oid_hex(s, &ce->oid)) {
 +static void numstat_patch_list(struct apply_state *state,
 +                             struct patch *patch)
 +{
 +      for ( ; patch; patch = patch->next) {
 +              const char *name;
 +              name = patch->new_name ? patch->new_name : patch->old_name;
 +              if (patch->is_binary)
 +                      printf("-\t-\t");
 +              else
 +                      printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
 +              write_name_quoted(name, stdout, state->line_termination);
 +      }
 +}
 +
 +static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name)
 +{
 +      if (mode)
 +              printf(" %s mode %06o %s\n", newdelete, mode, name);
 +      else
 +              printf(" %s %s\n", newdelete, name);
 +}
 +
 +static void show_mode_change(struct patch *p, int show_name)
 +{
 +      if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) {
 +              if (show_name)
 +                      printf(" mode change %06o => %06o %s\n",
 +                             p->old_mode, p->new_mode, p->new_name);
 +              else
 +                      printf(" mode change %06o => %06o\n",
 +                             p->old_mode, p->new_mode);
 +      }
 +}
 +
 +static void show_rename_copy(struct patch *p)
 +{
 +      const char *renamecopy = p->is_rename ? "rename" : "copy";
 +      const char *old, *new;
 +
 +      /* Find common prefix */
 +      old = p->old_name;
 +      new = p->new_name;
 +      while (1) {
 +              const char *slash_old, *slash_new;
 +              slash_old = strchr(old, '/');
 +              slash_new = strchr(new, '/');
 +              if (!slash_old ||
 +                  !slash_new ||
 +                  slash_old - old != slash_new - new ||
 +                  memcmp(old, new, slash_new - new))
 +                      break;
 +              old = slash_old + 1;
 +              new = slash_new + 1;
 +      }
 +      /* p->old_name thru old is the common prefix, and old and new
 +       * through the end of names are renames
 +       */
 +      if (old != p->old_name)
 +              printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
 +                     (int)(old - p->old_name), p->old_name,
 +                     old, new, p->score);
 +      else
 +              printf(" %s %s => %s (%d%%)\n", renamecopy,
 +                     p->old_name, p->new_name, p->score);
 +      show_mode_change(p, 0);
 +}
 +
 +static void summary_patch_list(struct patch *patch)
 +{
 +      struct patch *p;
 +
 +      for (p = patch; p; p = p->next) {
 +              if (p->is_new)
 +                      show_file_mode_name("create", p->new_mode, p->new_name);
 +              else if (p->is_delete)
 +                      show_file_mode_name("delete", p->old_mode, p->old_name);
 +              else {
 +                      if (p->is_rename || p->is_copy)
 +                              show_rename_copy(p);
 +                      else {
 +                              if (p->score) {
 +                                      printf(" rewrite %s (%d%%)\n",
 +                                             p->new_name, p->score);
 +                                      show_mode_change(p, 0);
 +                              }
 +                              else
 +                                      show_mode_change(p, 1);
 +                      }
 +              }
 +      }
 +}
 +
 +static void patch_stats(struct apply_state *state, struct patch *patch)
 +{
 +      int lines = patch->lines_added + patch->lines_deleted;
 +
 +      if (lines > state->max_change)
 +              state->max_change = lines;
 +      if (patch->old_name) {
 +              int len = quote_c_style(patch->old_name, NULL, NULL, 0);
 +              if (!len)
 +                      len = strlen(patch->old_name);
 +              if (len > state->max_len)
 +                      state->max_len = len;
 +      }
 +      if (patch->new_name) {
 +              int len = quote_c_style(patch->new_name, NULL, NULL, 0);
 +              if (!len)
 +                      len = strlen(patch->new_name);
 +              if (len > state->max_len)
 +                      state->max_len = len;
 +      }
 +}
 +
 +static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
 +{
 +      if (state->update_index) {
 +              if (remove_file_from_cache(patch->old_name) < 0)
 +                      return error(_("unable to remove %s from index"), patch->old_name);
 +      }
 +      if (!state->cached) {
 +              if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
 +                      remove_path(patch->old_name);
 +              }
 +      }
 +      return 0;
 +}
 +
 +static int add_index_file(struct apply_state *state,
 +                        const char *path,
 +                        unsigned mode,
 +                        void *buf,
 +                        unsigned long size)
 +{
 +      struct stat st;
 +      struct cache_entry *ce;
 +      int namelen = strlen(path);
 +      unsigned ce_size = cache_entry_size(namelen);
 +
 +      if (!state->update_index)
 +              return 0;
 +
 +      ce = xcalloc(1, ce_size);
 +      memcpy(ce->name, path, namelen);
 +      ce->ce_mode = create_ce_mode(mode);
 +      ce->ce_flags = create_ce_flags(0);
 +      ce->ce_namelen = namelen;
 +      if (S_ISGITLINK(mode)) {
 +              const char *s;
 +
 +              if (!skip_prefix(buf, "Subproject commit ", &s) ||
 +                  get_oid_hex(s, &ce->oid)) {
                        free(ce);
 -                      return error(_("corrupt patch for submodule %s"), path);
 +                     return error(_("corrupt patch for submodule %s"), path);
                }
        } else {
                if (!state->cached) {
diff --combined builtin/show-branch.c
index 4a6cc6f490f4e7b8a98adb362213535b6a9ae97d,3a5924293ae9259072cc6dc9570b935381467e72..3636a05594de18639bced97a1e18a128632bc00d
@@@ -5,6 -5,7 +5,7 @@@
  #include "color.h"
  #include "argv-array.h"
  #include "parse-options.h"
+ #include "dir.h"
  
  static const char* show_branch_usage[] = {
      N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
@@@ -358,7 -359,7 +359,7 @@@ static void sort_ref_range(int bottom, 
  static int append_ref(const char *refname, const struct object_id *oid,
                      int allow_dups)
  {
 -      struct commit *commit = lookup_commit_reference_gently(oid->hash, 1);
 +      struct commit *commit = lookup_commit_reference_gently(oid, 1);
        int i;
  
        if (!commit)
@@@ -421,14 -422,6 +422,6 @@@ static int append_tag_ref(const char *r
  
  static const char *match_ref_pattern = NULL;
  static int match_ref_slash = 0;
- static int count_slash(const char *s)
- {
-       int cnt = 0;
-       while (*s)
-               if (*s++ == '/')
-                       cnt++;
-       return cnt;
- }
  
  static int append_matching_ref(const char *refname, const struct object_id *oid,
                               int flag, void *cb_data)
         * refs/tags/v0.99.9a and friends.
         */
        const char *tail;
-       int slash = count_slash(refname);
+       int slash = count_slashes(refname);
        for (tail = refname; *tail && match_ref_slash < slash; )
                if (*tail++ == '/')
                        slash--;
@@@ -529,7 -522,7 +522,7 @@@ static void append_one_rev(const char *
                int saved_matches = ref_name_cnt;
  
                match_ref_pattern = av;
-               match_ref_slash = count_slash(av);
+               match_ref_slash = count_slashes(av);
                for_each_ref(append_matching_ref, NULL);
                if (saved_matches == ref_name_cnt &&
                    ref_name_cnt < MAX_REVS)
@@@ -735,7 -728,7 +728,7 @@@ int cmd_show_branch(int ac, const char 
                        base = strtoul(reflog_base, &ep, 10);
                        if (*ep) {
                                /* Ah, that is a date spec... */
 -                              unsigned long at;
 +                              timestamp_t at;
                                at = approxidate(reflog_base);
                                read_ref_at(ref, flags, at, -1, oid.hash, NULL,
                                            NULL, NULL, &base);
                        char *logmsg;
                        char *nth_desc;
                        const char *msg;
 -                      unsigned long timestamp;
 +                      timestamp_t timestamp;
                        int tz;
  
                        if (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,
                               MAX_REVS), MAX_REVS);
                if (get_sha1(ref_name[num_rev], revkey.hash))
                        die(_("'%s' is not a valid ref."), ref_name[num_rev]);
 -              commit = lookup_commit_reference(revkey.hash);
 +              commit = lookup_commit_reference(&revkey);
                if (!commit)
                        die(_("cannot find commit %s (%s)"),
                            ref_name[num_rev], oid_to_hex(&revkey));
diff --combined dir.c
index 17590638176f26e35f3a728e5cd56917e0568541,a870f42ddc9aecfd571b753df14af363b2872cde..5f1afb56bc6e6d5dc5300380f980f4b2699ab08d
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -7,7 -7,6 +7,7 @@@
   * Copyright (C) Linus Torvalds, 2005-2006
   *             Junio Hamano, 2005-2006
   */
 +#define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
  #include "dir.h"
  #include "attr.h"
@@@ -46,12 -45,19 +46,21 @@@ struct cached_dir 
  };
  
  static enum path_treatment read_directory_recursive(struct dir_struct *dir,
 -      const char *path, int len, struct untracked_cache_dir *untracked,
 +      struct index_state *istate, const char *path, int len,
 +      struct untracked_cache_dir *untracked,
        int check_only, const struct pathspec *pathspec);
 -static int get_dtype(struct dirent *de, const char *path, int len);
 +static int get_dtype(struct dirent *de, struct index_state *istate,
 +                   const char *path, int len);
  
+ int count_slashes(const char *s)
+ {
+       int cnt = 0;
+       while (*s)
+               if (*s++ == '/')
+                       cnt++;
+       return cnt;
+ }
  int fspathcmp(const char *a, const char *b)
  {
        return ignore_case ? strcasecmp(a, b) : strcmp(a, b);
@@@ -177,9 -183,7 +186,9 @@@ char *common_prefix(const struct pathsp
        return len ? xmemdupz(pathspec->items[0].match, len) : NULL;
  }
  
 -int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)
 +int fill_directory(struct dir_struct *dir,
 +                 struct index_state *istate,
 +                 const struct pathspec *pathspec)
  {
        const char *prefix;
        size_t prefix_len;
        prefix = prefix_len ? pathspec->items[0].match : "";
  
        /* Read the directory and prune it */
 -      read_directory(dir, prefix, prefix_len, pathspec);
 +      read_directory(dir, istate, prefix, prefix_len, pathspec);
  
        return prefix_len;
  }
@@@ -592,8 -596,7 +601,8 @@@ void add_exclude(const char *string, co
        x->el = el;
  }
  
 -static void *read_skip_worktree_file_from_index(const char *path, size_t *size,
 +static void *read_skip_worktree_file_from_index(const struct index_state *istate,
 +                                              const char *path, size_t *size,
                                                struct sha1_stat *sha1_stat)
  {
        int pos, len;
        void *data;
  
        len = strlen(path);
 -      pos = cache_name_pos(path, len);
 +      pos = index_name_pos(istate, path, len);
        if (pos < 0)
                return NULL;
 -      if (!ce_skip_worktree(active_cache[pos]))
 +      if (!ce_skip_worktree(istate->cache[pos]))
                return NULL;
 -      data = read_sha1_file(active_cache[pos]->oid.hash, &type, &sz);
 +      data = read_sha1_file(istate->cache[pos]->oid.hash, &type, &sz);
        if (!data || type != OBJ_BLOB) {
                free(data);
                return NULL;
        *size = xsize_t(sz);
        if (sha1_stat) {
                memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat));
 -              hashcpy(sha1_stat->sha1, active_cache[pos]->oid.hash);
 +              hashcpy(sha1_stat->sha1, istate->cache[pos]->oid.hash);
        }
        return data;
  }
@@@ -733,7 -736,7 +742,7 @@@ static void invalidate_directory(struc
  
  /*
   * Given a file with name "fname", read it (either from disk, or from
 - * the index if "check_index" is non-zero), parse it and store the
 + * an index if 'istate' is non-null), parse it and store the
   * exclude rules in "el".
   *
   * If "ss" is not NULL, compute SHA-1 of the exclude file and fill
   * ss_valid is non-zero, "ss" must contain good value as input.
   */
  static int add_excludes(const char *fname, const char *base, int baselen,
 -                      struct exclude_list *el, int check_index,
 +                      struct exclude_list *el,
 +                      struct index_state *istate,
                        struct sha1_stat *sha1_stat)
  {
        struct stat st;
  
        fd = open(fname, O_RDONLY);
        if (fd < 0 || fstat(fd, &st) < 0) {
 -              if (errno != ENOENT)
 -                      warn_on_inaccessible(fname);
 -              if (0 <= fd)
 +              if (fd < 0)
 +                      warn_on_fopen_errors(fname);
 +              else
                        close(fd);
 -              if (!check_index ||
 -                  (buf = read_skip_worktree_file_from_index(fname, &size, sha1_stat)) == NULL)
 +              if (!istate ||
 +                  (buf = read_skip_worktree_file_from_index(istate, fname, &size, sha1_stat)) == NULL)
                        return -1;
                if (size == 0) {
                        free(buf);
                if (sha1_stat) {
                        int pos;
                        if (sha1_stat->valid &&
 -                          !match_stat_data_racy(&the_index, &sha1_stat->stat, &st))
 +                          !match_stat_data_racy(istate, &sha1_stat->stat, &st))
                                ; /* no content change, ss->sha1 still good */
 -                      else if (check_index &&
 -                               (pos = cache_name_pos(fname, strlen(fname))) >= 0 &&
 -                               !ce_stage(active_cache[pos]) &&
 -                               ce_uptodate(active_cache[pos]) &&
 +                      else if (istate &&
 +                               (pos = index_name_pos(istate, fname, strlen(fname))) >= 0 &&
 +                               !ce_stage(istate->cache[pos]) &&
 +                               ce_uptodate(istate->cache[pos]) &&
                                 !would_convert_to_git(fname))
                                hashcpy(sha1_stat->sha1,
 -                                      active_cache[pos]->oid.hash);
 +                                      istate->cache[pos]->oid.hash);
                        else
                                hash_sha1_file(buf, size, "blob", sha1_stat->sha1);
                        fill_stat_data(&sha1_stat->stat, &st);
  
  int add_excludes_from_file_to_list(const char *fname, const char *base,
                                   int baselen, struct exclude_list *el,
 -                                 int check_index)
 +                                 struct index_state *istate)
  {
 -      return add_excludes(fname, base, baselen, el, check_index, NULL);
 +      return add_excludes(fname, base, baselen, el, istate, NULL);
  }
  
  struct exclude_list *add_exclude_list(struct dir_struct *dir,
@@@ -862,7 -864,7 +871,7 @@@ static void add_excludes_from_file_1(st
        if (!dir->untracked)
                dir->unmanaged_exclude_files++;
        el = add_exclude_list(dir, EXC_FILE, fname);
 -      if (add_excludes(fname, "", 0, el, 0, sha1_stat) < 0)
 +      if (add_excludes(fname, "", 0, el, NULL, sha1_stat) < 0)
                die("cannot use %s as an exclude file", fname);
  }
  
@@@ -965,8 -967,7 +974,8 @@@ static struct exclude *last_exclude_mat
                                                       int pathlen,
                                                       const char *basename,
                                                       int *dtype,
 -                                                     struct exclude_list *el)
 +                                                     struct exclude_list *el,
 +                                                     struct index_state *istate)
  {
        struct exclude *exc = NULL; /* undecided */
        int i;
  
                if (x->flags & EXC_FLAG_MUSTBEDIR) {
                        if (*dtype == DT_UNKNOWN)
 -                              *dtype = get_dtype(NULL, pathname, pathlen);
 +                              *dtype = get_dtype(NULL, istate, pathname, pathlen);
                        if (*dtype != DT_DIR)
                                continue;
                }
   */
  int is_excluded_from_list(const char *pathname,
                          int pathlen, const char *basename, int *dtype,
 -                        struct exclude_list *el)
 +                        struct exclude_list *el, struct index_state *istate)
  {
        struct exclude *exclude;
 -      exclude = last_exclude_matching_from_list(pathname, pathlen, basename, dtype, el);
 +      exclude = last_exclude_matching_from_list(pathname, pathlen, basename,
 +                                                dtype, el, istate);
        if (exclude)
                return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
        return -1; /* undecided */
  }
  
  static struct exclude *last_exclude_matching_from_lists(struct dir_struct *dir,
 +                                                      struct index_state *istate,
                const char *pathname, int pathlen, const char *basename,
                int *dtype_p)
  {
                for (j = group->nr - 1; j >= 0; j--) {
                        exclude = last_exclude_matching_from_list(
                                pathname, pathlen, basename, dtype_p,
 -                              &group->el[j]);
 +                              &group->el[j], istate);
                        if (exclude)
                                return exclude;
                }
   * Loads the per-directory exclude list for the substring of base
   * which has a char length of baselen.
   */
 -static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
 +static void prep_exclude(struct dir_struct *dir,
 +                       struct index_state *istate,
 +                       const char *base, int baselen)
  {
        struct exclude_list_group *group;
        struct exclude_list *el;
                        int dt = DT_DIR;
                        dir->basebuf.buf[stk->baselen - 1] = 0;
                        dir->exclude = last_exclude_matching_from_lists(dir,
 +                                                                      istate,
                                dir->basebuf.buf, stk->baselen - 1,
                                dir->basebuf.buf + current, &dt);
                        dir->basebuf.buf[stk->baselen - 1] = '/';
                        strbuf_addbuf(&sb, &dir->basebuf);
                        strbuf_addstr(&sb, dir->exclude_per_dir);
                        el->src = strbuf_detach(&sb, NULL);
 -                      add_excludes(el->src, el->src, stk->baselen, el, 1,
 +                      add_excludes(el->src, el->src, stk->baselen, el, istate,
                                     untracked ? &sha1_stat : NULL);
                }
                /*
   * undecided.
   */
  struct exclude *last_exclude_matching(struct dir_struct *dir,
 -                                           const char *pathname,
 -                                           int *dtype_p)
 +                                    struct index_state *istate,
 +                                    const char *pathname,
 +                                    int *dtype_p)
  {
        int pathlen = strlen(pathname);
        const char *basename = strrchr(pathname, '/');
        basename = (basename) ? basename+1 : pathname;
  
 -      prep_exclude(dir, pathname, basename-pathname);
 +      prep_exclude(dir, istate, pathname, basename-pathname);
  
        if (dir->exclude)
                return dir->exclude;
  
 -      return last_exclude_matching_from_lists(dir, pathname, pathlen,
 +      return last_exclude_matching_from_lists(dir, istate, pathname, pathlen,
                        basename, dtype_p);
  }
  
   * scans all exclude lists to determine whether pathname is excluded.
   * Returns 1 if true, otherwise 0.
   */
 -int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
 +int is_excluded(struct dir_struct *dir, struct index_state *istate,
 +              const char *pathname, int *dtype_p)
  {
        struct exclude *exclude =
 -              last_exclude_matching(dir, pathname, dtype_p);
 +              last_exclude_matching(dir, istate, pathname, dtype_p);
        if (exclude)
                return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
        return 0;
@@@ -1248,22 -1242,18 +1257,22 @@@ static struct dir_entry *dir_entry_new(
        return ent;
  }
  
 -static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
 +static struct dir_entry *dir_add_name(struct dir_struct *dir,
 +                                    struct index_state *istate,
 +                                    const char *pathname, int len)
  {
 -      if (cache_file_exists(pathname, len, ignore_case))
 +      if (index_file_exists(istate, pathname, len, ignore_case))
                return NULL;
  
        ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
        return dir->entries[dir->nr++] = dir_entry_new(pathname, len);
  }
  
 -struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len)
 +struct dir_entry *dir_add_ignored(struct dir_struct *dir,
 +                                struct index_state *istate,
 +                                const char *pathname, int len)
  {
 -      if (!cache_name_is_other(pathname, len))
 +      if (!index_name_is_other(istate, pathname, len))
                return NULL;
  
        ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc);
@@@ -1281,15 -1271,14 +1290,15 @@@ enum exist_status 
   * the directory name; instead, use the case insensitive
   * directory hash.
   */
 -static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)
 +static enum exist_status directory_exists_in_index_icase(struct index_state *istate,
 +                                                       const char *dirname, int len)
  {
        struct cache_entry *ce;
  
 -      if (cache_dir_exists(dirname, len))
 +      if (index_dir_exists(istate, dirname, len))
                return index_directory;
  
 -      ce = cache_file_exists(dirname, len, ignore_case);
 +      ce = index_file_exists(istate, dirname, len, ignore_case);
        if (ce && S_ISGITLINK(ce->ce_mode))
                return index_gitdir;
  
   * the files it contains) will sort with the '/' at the
   * end.
   */
 -static enum exist_status directory_exists_in_index(const char *dirname, int len)
 +static enum exist_status directory_exists_in_index(struct index_state *istate,
 +                                                 const char *dirname, int len)
  {
        int pos;
  
        if (ignore_case)
 -              return directory_exists_in_index_icase(dirname, len);
 +              return directory_exists_in_index_icase(istate, dirname, len);
  
 -      pos = cache_name_pos(dirname, len);
 +      pos = index_name_pos(istate, dirname, len);
        if (pos < 0)
                pos = -pos-1;
 -      while (pos < active_nr) {
 -              const struct cache_entry *ce = active_cache[pos++];
 +      while (pos < istate->cache_nr) {
 +              const struct cache_entry *ce = istate->cache[pos++];
                unsigned char endchar;
  
                if (strncmp(ce->name, dirname, len))
   *  (c) otherwise, we recurse into it.
   */
  static enum path_treatment treat_directory(struct dir_struct *dir,
 +      struct index_state *istate,
        struct untracked_cache_dir *untracked,
        const char *dirname, int len, int baselen, int exclude,
        const struct pathspec *pathspec)
  {
        /* The "len-1" is to strip the final '/' */
 -      switch (directory_exists_in_index(dirname, len-1)) {
 +      switch (directory_exists_in_index(istate, dirname, len-1)) {
        case index_directory:
                return path_recurse;
  
  
        untracked = lookup_untracked(dir->untracked, untracked,
                                     dirname + baselen, len - baselen);
 -      return read_directory_recursive(dir, dirname, len,
 +      return read_directory_recursive(dir, istate, dirname, len,
                                        untracked, 1, pathspec);
  }
  
@@@ -1477,13 -1464,12 +1486,13 @@@ static int exclude_matches_pathspec(con
        return 0;
  }
  
 -static int get_index_dtype(const char *path, int len)
 +static int get_index_dtype(struct index_state *istate,
 +                         const char *path, int len)
  {
        int pos;
        const struct cache_entry *ce;
  
 -      ce = cache_file_exists(path, len, 0);
 +      ce = index_file_exists(istate, path, len, 0);
        if (ce) {
                if (!ce_uptodate(ce))
                        return DT_UNKNOWN;
        }
  
        /* Try to look it up as a directory */
 -      pos = cache_name_pos(path, len);
 +      pos = index_name_pos(istate, path, len);
        if (pos >= 0)
                return DT_UNKNOWN;
        pos = -pos-1;
 -      while (pos < active_nr) {
 -              ce = active_cache[pos++];
 +      while (pos < istate->cache_nr) {
 +              ce = istate->cache[pos++];
                if (strncmp(ce->name, path, len))
                        break;
                if (ce->name[len] > '/')
        return DT_UNKNOWN;
  }
  
 -static int get_dtype(struct dirent *de, const char *path, int len)
 +static int get_dtype(struct dirent *de, struct index_state *istate,
 +                   const char *path, int len)
  {
        int dtype = de ? DTYPE(de) : DT_UNKNOWN;
        struct stat st;
  
        if (dtype != DT_UNKNOWN)
                return dtype;
 -      dtype = get_index_dtype(path, len);
 +      dtype = get_index_dtype(istate, path, len);
        if (dtype != DT_UNKNOWN)
                return dtype;
        if (lstat(path, &st))
  
  static enum path_treatment treat_one_path(struct dir_struct *dir,
                                          struct untracked_cache_dir *untracked,
 +                                        struct index_state *istate,
                                          struct strbuf *path,
                                          int baselen,
                                          const struct pathspec *pathspec,
                                          int dtype, struct dirent *de)
  {
        int exclude;
 -      int has_path_in_index = !!cache_file_exists(path->buf, path->len, ignore_case);
 +      int has_path_in_index = !!index_file_exists(istate, path->buf, path->len, ignore_case);
  
        if (dtype == DT_UNKNOWN)
 -              dtype = get_dtype(de, path->buf, path->len);
 +              dtype = get_dtype(de, istate, path->buf, path->len);
  
        /* Always exclude indexed files */
        if (dtype != DT_DIR && has_path_in_index)
        if ((dir->flags & DIR_COLLECT_KILLED_ONLY) &&
            (dtype == DT_DIR) &&
            !has_path_in_index &&
 -          (directory_exists_in_index(path->buf, path->len) == index_nonexistent))
 +          (directory_exists_in_index(istate, path->buf, path->len) == index_nonexistent))
                return path_none;
  
 -      exclude = is_excluded(dir, path->buf, &dtype);
 +      exclude = is_excluded(dir, istate, path->buf, &dtype);
  
        /*
         * Excluded? If we don't explicitly want to show
                return path_none;
        case DT_DIR:
                strbuf_addch(path, '/');
 -              return treat_directory(dir, untracked, path->buf, path->len,
 +              return treat_directory(dir, istate, untracked, path->buf, path->len,
                                       baselen, exclude, pathspec);
        case DT_REG:
        case DT_LNK:
  static enum path_treatment treat_path_fast(struct dir_struct *dir,
                                           struct untracked_cache_dir *untracked,
                                           struct cached_dir *cdir,
 +                                         struct index_state *istate,
                                           struct strbuf *path,
                                           int baselen,
                                           const struct pathspec *pathspec)
                 * to its bottom. Verify again the same set of directories
                 * with check_only set.
                 */
 -              return read_directory_recursive(dir, path->buf, path->len,
 +              return read_directory_recursive(dir, istate, path->buf, path->len,
                                                cdir->ucd, 1, pathspec);
        /*
         * We get path_recurse in the first run when
  static enum path_treatment treat_path(struct dir_struct *dir,
                                      struct untracked_cache_dir *untracked,
                                      struct cached_dir *cdir,
 +                                    struct index_state *istate,
                                      struct strbuf *path,
                                      int baselen,
                                      const struct pathspec *pathspec)
        struct dirent *de = cdir->de;
  
        if (!de)
 -              return treat_path_fast(dir, untracked, cdir, path,
 +              return treat_path_fast(dir, untracked, cdir, istate, path,
                                       baselen, pathspec);
        if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git"))
                return path_none;
                return path_none;
  
        dtype = DTYPE(de);
 -      return treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de);
 +      return treat_one_path(dir, untracked, istate, path, baselen, pathspec, dtype, de);
  }
  
  static void add_untracked(struct untracked_cache_dir *dir, const char *name)
  
  static int valid_cached_dir(struct dir_struct *dir,
                            struct untracked_cache_dir *untracked,
 +                          struct index_state *istate,
                            struct strbuf *path,
                            int check_only)
  {
                return 0;
        }
        if (!untracked->valid ||
 -          match_stat_data_racy(&the_index, &untracked->stat_data, &st)) {
 +          match_stat_data_racy(istate, &untracked->stat_data, &st)) {
                if (untracked->valid)
                        invalidate_directory(dir->untracked, untracked);
                fill_stat_data(&untracked->stat_data, &st);
         */
        if (path->len && path->buf[path->len - 1] != '/') {
                strbuf_addch(path, '/');
 -              prep_exclude(dir, path->buf, path->len);
 +              prep_exclude(dir, istate, path->buf, path->len);
                strbuf_setlen(path, path->len - 1);
        } else
 -              prep_exclude(dir, path->buf, path->len);
 +              prep_exclude(dir, istate, path->buf, path->len);
  
        /* hopefully prep_exclude() haven't invalidated this entry... */
        return untracked->valid;
  static int open_cached_dir(struct cached_dir *cdir,
                           struct dir_struct *dir,
                           struct untracked_cache_dir *untracked,
 +                         struct index_state *istate,
                           struct strbuf *path,
                           int check_only)
  {
        memset(cdir, 0, sizeof(*cdir));
        cdir->untracked = untracked;
 -      if (valid_cached_dir(dir, untracked, path, check_only))
 +      if (valid_cached_dir(dir, untracked, istate, path, check_only))
                return 0;
        cdir->fdir = opendir(path->len ? path->buf : ".");
        if (dir->untracked)
@@@ -1788,9 -1768,9 +1797,9 @@@ static void close_cached_dir(struct cac
   * Returns the most significant path_treatment value encountered in the scan.
   */
  static enum path_treatment read_directory_recursive(struct dir_struct *dir,
 -                                  const char *base, int baselen,
 -                                  struct untracked_cache_dir *untracked, int check_only,
 -                                  const struct pathspec *pathspec)
 +      struct index_state *istate, const char *base, int baselen,
 +      struct untracked_cache_dir *untracked, int check_only,
 +      const struct pathspec *pathspec)
  {
        struct cached_dir cdir;
        enum path_treatment state, subdir_state, dir_state = path_none;
  
        strbuf_add(&path, base, baselen);
  
 -      if (open_cached_dir(&cdir, dir, untracked, &path, check_only))
 +      if (open_cached_dir(&cdir, dir, untracked, istate, &path, check_only))
                goto out;
  
        if (untracked)
  
        while (!read_cached_dir(&cdir)) {
                /* check how the file or directory should be treated */
 -              state = treat_path(dir, untracked, &cdir, &path,
 +              state = treat_path(dir, untracked, &cdir, istate, &path,
                                   baselen, pathspec);
  
                if (state > dir_state)
                        dir_state = state;
  
                /* recurse into subdir if instructed by treat_path */
 -              if (state == path_recurse) {
 +              if ((state == path_recurse) ||
 +                      ((state == path_untracked) &&
 +                       (dir->flags & DIR_SHOW_IGNORED_TOO) &&
 +                       (get_dtype(cdir.de, istate, path.buf, path.len) == DT_DIR))) {
                        struct untracked_cache_dir *ud;
                        ud = lookup_untracked(dir->untracked, untracked,
                                              path.buf + baselen,
                                              path.len - baselen);
                        subdir_state =
 -                              read_directory_recursive(dir, path.buf,
 +                              read_directory_recursive(dir, istate, path.buf,
                                                         path.len, ud,
                                                         check_only, pathspec);
                        if (subdir_state > dir_state)
                switch (state) {
                case path_excluded:
                        if (dir->flags & DIR_SHOW_IGNORED)
 -                              dir_add_name(dir, path.buf, path.len);
 +                              dir_add_name(dir, istate, path.buf, path.len);
                        else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
                                ((dir->flags & DIR_COLLECT_IGNORED) &&
                                exclude_matches_pathspec(path.buf, path.len,
                                                         pathspec)))
 -                              dir_add_ignored(dir, path.buf, path.len);
 +                              dir_add_ignored(dir, istate, path.buf, path.len);
                        break;
  
                case path_untracked:
                        if (dir->flags & DIR_SHOW_IGNORED)
                                break;
 -                      dir_add_name(dir, path.buf, path.len);
 +                      dir_add_name(dir, istate, path.buf, path.len);
                        if (cdir.fdir)
                                add_untracked(untracked, path.buf + baselen);
                        break;
        return dir_state;
  }
  
 -static int cmp_name(const void *p1, const void *p2)
 +int cmp_dir_entry(const void *p1, const void *p2)
  {
        const struct dir_entry *e1 = *(const struct dir_entry **)p1;
        const struct dir_entry *e2 = *(const struct dir_entry **)p2;
        return name_compare(e1->name, e1->len, e2->name, e2->len);
  }
  
 +/* check if *out lexically strictly contains *in */
 +int check_dir_entry_contains(const struct dir_entry *out, const struct dir_entry *in)
 +{
 +      return (out->len < in->len) &&
 +              (out->name[out->len - 1] == '/') &&
 +              !memcmp(out->name, in->name, out->len);
 +}
 +
  static int treat_leading_path(struct dir_struct *dir,
 +                            struct index_state *istate,
                              const char *path, int len,
                              const struct pathspec *pathspec)
  {
                        break;
                if (simplify_away(sb.buf, sb.len, pathspec))
                        break;
 -              if (treat_one_path(dir, NULL, &sb, baselen, pathspec,
 +              if (treat_one_path(dir, NULL, istate, &sb, baselen, pathspec,
                                   DT_DIR, NULL) == path_none)
                        break; /* do not recurse into it */
                if (len <= baselen) {
@@@ -2084,8 -2052,8 +2093,8 @@@ static struct untracked_cache_dir *vali
        return root;
  }
  
 -int read_directory(struct dir_struct *dir, const char *path,
 -                 int len, const struct pathspec *pathspec)
 +int read_directory(struct dir_struct *dir, struct index_state *istate,
 +                 const char *path, int len, const struct pathspec *pathspec)
  {
        struct untracked_cache_dir *untracked;
  
                 * e.g. prep_exclude()
                 */
                dir->untracked = NULL;
 -      if (!len || treat_leading_path(dir, path, len, pathspec))
 -              read_directory_recursive(dir, path, len, untracked, 0, pathspec);
 -      QSORT(dir->entries, dir->nr, cmp_name);
 -      QSORT(dir->ignored, dir->ignored_nr, cmp_name);
 +      if (!len || treat_leading_path(dir, istate, path, len, pathspec))
 +              read_directory_recursive(dir, istate, path, len, untracked, 0, pathspec);
 +      QSORT(dir->entries, dir->nr, cmp_dir_entry);
 +      QSORT(dir->ignored, dir->ignored_nr, cmp_dir_entry);
 +
 +      /*
 +       * If DIR_SHOW_IGNORED_TOO is set, read_directory_recursive() will
 +       * also pick up untracked contents of untracked dirs; by default
 +       * we discard these, but given DIR_KEEP_UNTRACKED_CONTENTS we do not.
 +       */
 +      if ((dir->flags & DIR_SHOW_IGNORED_TOO) &&
 +                   !(dir->flags & DIR_KEEP_UNTRACKED_CONTENTS)) {
 +              int i, j;
 +
 +              /* remove from dir->entries untracked contents of untracked dirs */
 +              for (i = j = 0; j < dir->nr; j++) {
 +                      if (i &&
 +                          check_dir_entry_contains(dir->entries[i - 1], dir->entries[j])) {
 +                              free(dir->entries[j]);
 +                              dir->entries[j] = NULL;
 +                      } else {
 +                              dir->entries[i++] = dir->entries[j];
 +                      }
 +              }
 +
 +              dir->nr = i;
 +      }
 +
        if (dir->untracked) {
                static struct trace_key trace_untracked_stats = TRACE_KEY_INIT(UNTRACKED_STATS);
                trace_printf_key(&trace_untracked_stats,
                                 dir->untracked->gitignore_invalidated,
                                 dir->untracked->dir_invalidated,
                                 dir->untracked->dir_opened);
 -              if (dir->untracked == the_index.untracked &&
 +              if (dir->untracked == istate->untracked &&
                    (dir->untracked->dir_opened ||
                     dir->untracked->gitignore_invalidated ||
                     dir->untracked->dir_invalidated))
 -                      the_index.cache_changed |= UNTRACKED_CHANGED;
 -              if (dir->untracked != the_index.untracked) {
 +                      istate->cache_changed |= UNTRACKED_CHANGED;
 +              if (dir->untracked != istate->untracked) {
                        free(dir->untracked);
                        dir->untracked = NULL;
                }
@@@ -2337,7 -2281,7 +2346,7 @@@ int remove_path(const char *name
  {
        char *slash;
  
 -      if (unlink(name) && errno != ENOENT && errno != ENOTDIR)
 +      if (unlink(name) && !is_missing_file_error(errno))
                return -1;
  
        slash = strrchr(name, '/');
diff --combined dir.h
index a89c13e27a4fb55883f811a2c82fb465bb14988d,bdeeab7f7fd4d43f659310b894f463cedc748b98..e3717055d193366e6780b50d68f6a3c2360d32c4
--- 1/dir.h
--- 2/dir.h
+++ b/dir.h
@@@ -151,8 -151,7 +151,8 @@@ struct dir_struct 
                DIR_NO_GITLINKS = 1<<3,
                DIR_COLLECT_IGNORED = 1<<4,
                DIR_SHOW_IGNORED_TOO = 1<<5,
 -              DIR_COLLECT_KILLED_ONLY = 1<<6
 +              DIR_COLLECT_KILLED_ONLY = 1<<6,
 +              DIR_KEEP_UNTRACKED_CONTENTS = 1<<7
        } flags;
        struct dir_entry **entries;
        struct dir_entry **ignored;
        unsigned unmanaged_exclude_files;
  };
  
+ /*Count the number of slashes for string s*/
+ extern int count_slashes(const char *s);
  /*
   * The ordering of these constants is significant, with
   * higher-numbered match types signifying "closer" (i.e. more
@@@ -215,20 -217,12 +218,20 @@@ extern int match_pathspec(const struct 
  extern int report_path_error(const char *ps_matched, const struct pathspec *pathspec, const char *prefix);
  extern int within_depth(const char *name, int namelen, int depth, int max_depth);
  
 -extern int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec);
 -extern int read_directory(struct dir_struct *, const char *path, int len, const struct pathspec *pathspec);
 -
 -extern int is_excluded_from_list(const char *pathname, int pathlen, const char *basename,
 -                               int *dtype, struct exclude_list *el);
 -struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len);
 +extern int fill_directory(struct dir_struct *dir,
 +                        struct index_state *istate,
 +                        const struct pathspec *pathspec);
 +extern int read_directory(struct dir_struct *, struct index_state *istate,
 +                        const char *path, int len,
 +                        const struct pathspec *pathspec);
 +
 +extern int is_excluded_from_list(const char *pathname, int pathlen,
 +                               const char *basename, int *dtype,
 +                               struct exclude_list *el,
 +                               struct index_state *istate);
 +struct dir_entry *dir_add_ignored(struct dir_struct *dir,
 +                                struct index_state *istate,
 +                                const char *pathname, int len);
  
  /*
   * these implement the matching logic for dir.c:excluded_from_list and
@@@ -241,17 -235,14 +244,17 @@@ extern int match_pathname(const char *
                          const char *, int, int, unsigned);
  
  extern struct exclude *last_exclude_matching(struct dir_struct *dir,
 +                                           struct index_state *istate,
                                             const char *name, int *dtype);
  
 -extern int is_excluded(struct dir_struct *dir, const char *name, int *dtype);
 +extern int is_excluded(struct dir_struct *dir,
 +                     struct index_state *istate,
 +                     const char *name, int *dtype);
  
  extern struct exclude_list *add_exclude_list(struct dir_struct *dir,
                                             int group_type, const char *src);
  extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,
 -                                        struct exclude_list *el, int check_index);
 +                                        struct exclude_list *el, struct  index_state *istate);
  extern void add_excludes_from_file(struct dir_struct *, const char *fname);
  extern void parse_exclude_pattern(const char **string, int *patternlen, unsigned *flags, int *nowildcardlen);
  extern void add_exclude(const char *string, const char *base,
@@@ -338,9 -329,6 +341,9 @@@ static inline int dir_path_match(const 
                              has_trailing_dir);
  }
  
 +int cmp_dir_entry(const void *p1, const void *p2);
 +int check_dir_entry_contains(const struct dir_entry *out, const struct dir_entry *in);
 +
  void untracked_cache_invalidate_path(struct index_state *, const char *);
  void untracked_cache_remove_from_index(struct index_state *, const char *);
  void untracked_cache_add_to_index(struct index_state *, const char *);